Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFalk David <falkdavid@gmx.de>2020-09-12 12:43:55 +0300
committerFalk David <falkdavid@gmx.de>2020-09-12 12:43:55 +0300
commit8156e948042a464ca40ca78c946874340a8421f4 (patch)
tree903da71b516220f1113b68ce1b11ce4fff437aea
parent34063250aef35c2e4e03664da9ade24ca151f683 (diff)
parent91066cd0c3b9737feb85ea72abc7e021124639aa (diff)
Merge branch 'greasepencil-edit-curve' into soc-2020-greasepencil-curve
-rw-r--r--CMakeLists.txt48
-rw-r--r--build_files/cmake/platform/platform_apple_xcode.cmake8
-rw-r--r--build_files/cmake/platform/platform_win32.cmake4
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.cpp8
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.h10
-rw-r--r--extern/audaspace/include/file/FileWriter.h4
-rw-r--r--extern/audaspace/src/file/FileWriter.cpp20
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair_principled.h4
-rw-r--r--intern/ghost/test/multitest/MultiTest.c1
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h2
-rw-r--r--release/scripts/modules/rna_manual_reference.py72
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py23
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py1
-rw-r--r--release/scripts/startup/bl_ui/space_time.py43
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py76
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py5
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py3
-rw-r--r--release/scripts/templates_py/ui_menu.py2
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c2
-rw-r--r--source/blender/blenkernel/BKE_armature.h2
-rw-r--r--source/blender/blenkernel/BKE_customdata.h11
-rw-r--r--source/blender/blenkernel/BKE_displist.h28
-rw-r--r--source/blender/blenkernel/BKE_unit.h51
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_inline.h6
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c6
-rw-r--r--source/blender/blenkernel/intern/armature.c8
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c13
-rw-r--r--source/blender/blenkernel/intern/blendfile.c6
-rw-r--r--source/blender/blenkernel/intern/boids.c130
-rw-r--r--source/blender/blenkernel/intern/collection.c10
-rw-r--r--source/blender/blenkernel/intern/customdata.c27
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4
-rw-r--r--source/blender/blenkernel/intern/idtype.c26
-rw-r--r--source/blender/blenkernel/intern/image_gpu.c4
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c2
-rw-r--r--source/blender/blenkernel/intern/lib_override.c24
-rw-r--r--source/blender/blenkernel/intern/mesh.c44
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c14
-rw-r--r--source/blender/blenkernel/intern/scene.c8
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c152
-rw-r--r--source/blender/blenlib/BLI_array.hh4
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh20
-rw-r--r--source/blender/blenlib/BLI_string_search.h51
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh114
-rw-r--r--source/blender/blenlib/BLI_vector_set_slots.hh12
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/intern/polyfill_2d.c13
-rw-r--r--source/blender/blenlib/intern/string_search.cc475
-rw-r--r--source/blender/blenlib/tests/BLI_string_search_test.cc50
-rw-r--r--source/blender/blenlib/tests/BLI_vector_set_test.cc71
-rw-r--r--source/blender/blenloader/BLO_readfile.h76
-rw-r--r--source/blender/blenloader/intern/readfile.c241
-rw-r--r--source/blender/blenloader/intern/versioning_280.c8
-rw-r--r--source/blender/blenloader/intern/versioning_290.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c34
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h2
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c42
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_opaque.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c2
-rw-r--r--source/blender/draw/intern/DRW_render.h1
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c29
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c1
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c23
-rw-r--r--source/blender/draw/intern/draw_manager_text.c29
-rw-r--r--source/blender/draw/tests/shaders_test.cc30
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c34
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_mask.h4
-rw-r--r--source/blender/editors/include/ED_object.h3
-rw-r--r--source/blender/editors/interface/interface.c57
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c14
-rw-r--r--source/blender/editors/interface/interface_handlers.c4
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c26
-rw-r--r--source/blender/editors/interface/interface_templates.c160
-rw-r--r--source/blender/editors/io/io_alembic.c9
-rw-r--r--source/blender/editors/mask/mask_editaction.c18
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c14
-rw-r--r--source/blender/editors/mesh/meshtools.c9
-rw-r--r--source/blender/editors/object/object_add.c4
-rw-r--r--source/blender/editors/object/object_constraint.c80
-rw-r--r--source/blender/editors/object/object_data_transfer.c2
-rw-r--r--source/blender/editors/object/object_relations.c436
-rw-r--r--source/blender/editors/object/object_select.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c179
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c477
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c20
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h6
-rw-r--r--source/blender/editors/sound/sound_ops.c8
-rw-r--r--source/blender/editors/space_info/info_stats.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c145
-rw-r--r--source/blender/editors/space_node/node_draw.c110
-rw-r--r--source/blender/editors/space_node/node_select.c48
-rw-r--r--source/blender/editors/space_text/text_format.h2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c27
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c16
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c6
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c28
-rw-r--r--source/blender/editors/util/numinput.c40
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp2
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp2
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp2
-rw-r--r--source/blender/freestyle/intern/stroke/Predicates1D.h4
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h2
-rw-r--r--source/blender/gpu/CMakeLists.txt29
-rw-r--r--source/blender/gpu/GPU_capabilities.h (renamed from source/blender/gpu/GPU_extensions.h)24
-rw-r--r--source/blender/gpu/GPU_context.h5
-rw-r--r--source/blender/gpu/GPU_drawlist.h11
-rw-r--r--source/blender/gpu/GPU_framebuffer.h9
-rw-r--r--source/blender/gpu/GPU_immediate.h6
-rw-r--r--source/blender/gpu/GPU_index_buffer.h6
-rw-r--r--source/blender/gpu/GPU_state.h1
-rw-r--r--source/blender/gpu/GPU_texture.h8
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h6
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h1
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh8
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc3
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc127
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh55
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c2
-rw-r--r--source/blender/gpu/intern/gpu_context.cc93
-rw-r--r--source/blender/gpu/intern/gpu_context_private.hh71
-rw-r--r--source/blender/gpu/intern/gpu_drawlist.cc16
-rw-r--r--source/blender/gpu/intern/gpu_drawlist_private.hh16
-rw-r--r--source/blender/gpu/intern/gpu_extensions.cc441
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc83
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer_private.hh14
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc14
-rw-r--r--source/blender/gpu/intern/gpu_immediate_private.hh5
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c13
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc16
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc217
-rw-r--r--source/blender/gpu/intern/gpu_platform_private.hh53
-rw-r--r--source/blender/gpu/intern/gpu_private.h8
-rw-r--r--source/blender/gpu/intern/gpu_query.cc28
-rw-r--r--source/blender/gpu/intern/gpu_query.hh59
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c14
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h8
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc (renamed from source/blender/gpu/intern/gpu_select_sample_query.c)85
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc41
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c1
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.hh16
-rw-r--r--source/blender/gpu/intern/gpu_state.cc46
-rw-r--r--source/blender/gpu/intern/gpu_state_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc38
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh20
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer.cc15
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer_private.hh14
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh4
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc370
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh31
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc19
-rw-r--r--source/blender/gpu/opengl/gl_context.cc71
-rw-r--r--source/blender/gpu/opengl/gl_context.hh54
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc4
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc15
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc30
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.hh14
-rw-r--r--source/blender/gpu/opengl/gl_immediate.cc6
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc4
-rw-r--r--source/blender/gpu/opengl/gl_query.cc78
-rw-r--r--source/blender/gpu/opengl/gl_query.hh69
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc22
-rw-r--r--source/blender/gpu/opengl/gl_state.cc7
-rw-r--r--source/blender/gpu/opengl/gl_state.hh2
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc50
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh1
-rw-r--r--source/blender/gpu/opengl/gl_uniform_buffer.cc19
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc2
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.cc8
-rw-r--r--source/blender/gpu/tests/gpu_testing.cc31
-rw-r--r--source/blender/gpu/tests/gpu_testing.hh27
-rw-r--r--source/blender/imbuf/intern/util_gpu.c2
-rw-r--r--source/blender/io/alembic/ABC_alembic.h1
-rw-r--r--source/blender/io/alembic/CMakeLists.txt2
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc76
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.h6
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_instance.cc74
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_instance.h48
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp2
-rw-r--r--source/blender/io/collada/TransformWriter.cpp2
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.cc27
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h4
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc23
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h6
-rw-r--r--source/blender/makesdna/DNA_scene_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h10
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/RNA_types.h4
-rw-r--r--source/blender/makesrna/intern/makesrna.c4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c5
-rw-r--r--source/blender/makesrna/intern/rna_object.c35
-rw-r--r--source/blender/makesrna/intern/rna_render.c2
-rw-r--r--source/blender/makesrna/intern/rna_rna.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c30
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c6
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c11
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c4
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c21
-rw-r--r--source/blender/python/intern/bpy_library_load.c9
-rw-r--r--source/blender/python/intern/bpy_props.c1
-rw-r--r--source/blender/python/intern/bpy_rna.c4
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c4
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.h2
-rw-r--r--source/blender/python/intern/bpy_utils_units.c9
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/shader_fx/intern/FX_shader_light.c106
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c34
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c1
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c3
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c2
-rw-r--r--source/blender/windowmanager/intern/wm_surface.c3
-rw-r--r--source/blender/windowmanager/intern/wm_window.c2
235 files changed, 4947 insertions, 2651 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 76d2d578dc3..cfc49505a0b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -128,7 +128,9 @@ enable_testing()
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin CACHE INTERNAL "" FORCE)
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib CACHE INTERNAL "" FORCE)
-if(MSVC)
+
+get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(GENERATOR_IS_MULTI_CONFIG)
set(TESTS_OUTPUT_DIR ${EXECUTABLE_OUTPUT_PATH}/tests/$<CONFIG>/ CACHE INTERNAL "" FORCE)
else()
set(TESTS_OUTPUT_DIR ${EXECUTABLE_OUTPUT_PATH}/tests/ CACHE INTERNAL "" FORCE)
@@ -510,9 +512,21 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
-fno-sanitize=alignment \
")
- if(NOT MSVC) # not all sanitizers are supported with clang-cl, these two however are very vocal about it
- set(_asan_defaults "${_asan_defaults} -fsanitize=leak -fsanitize=object-size" )
+ if(MSVC)
+ # clang-cl doesn't support all sanitizers, but leak and object-size give errors/warnings.
+ set(_asan_defaults "${_asan_defaults}")
+ elseif(APPLE)
+ # AppleClang doesn't support all sanitizers, but leak gives error.
+ if(CMAKE_BUILD_TYPE MATCHES "Debug")
+ # Silence the warning that object-size is not effective in -O0.
+ set(_asan_defaults "${_asan_defaults}")
+ else()
+ set(_asan_defaults "${_asan_defaults} -fsanitize=object-size")
+ endif()
+ else()
+ set(_asan_defaults "${_asan_defaults} -fsanitize=leak -fsanitize=object-size")
endif()
+
set(COMPILER_ASAN_CFLAGS "${_asan_defaults}" CACHE STRING "C flags for address sanitizer")
mark_as_advanced(COMPILER_ASAN_CFLAGS)
set(COMPILER_ASAN_CXXFLAGS "${_asan_defaults}" CACHE STRING "C++ flags for address sanitizer")
@@ -520,16 +534,31 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
unset(_asan_defaults)
- if(NOT MSVC)
- find_library(COMPILER_ASAN_LIBRARY asan ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES})
- else()
- find_library(
- COMPILER_ASAN_LIBRARY NAMES clang_rt.asan-x86_64
+ if(MSVC)
+ find_library(
+ COMPILER_ASAN_LIBRARY NAMES clang_rt.asan-x86_64
PATHS
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
)
+ elseif(APPLE)
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER}
+ -print-file-name=lib
+ OUTPUT_VARIABLE CLANG_LIB_DIR
+ )
+ string(STRIP "${CLANG_LIB_DIR}" CLANG_LIB_DIR)
+ find_library(
+ COMPILER_ASAN_LIBRARY NAMES libclang_rt.asan_osx_dynamic.dylib
+ PATHS
+ "${CLANG_LIB_DIR}/darwin/"
+ )
+ unset(CLANG_LIB_DIR)
+ else()
+ find_library(
+ COMPILER_ASAN_LIBRARY asan ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}
+ )
endif()
+
mark_as_advanced(COMPILER_ASAN_LIBRARY)
endif()
endif()
@@ -823,6 +852,9 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Release")
if(MSVC)
set(COMPILER_ASAN_LINKER_FLAGS "/FUNCTIONPADMIN:6")
endif()
+ if(APPLE)
+ set(COMPILER_ASAN_LINKER_FLAGS "-fno-omit-frame-pointer -fsanitize=address")
+ endif(APPLE)
if(COMPILER_ASAN_LIBRARY)
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}")
set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
diff --git a/build_files/cmake/platform/platform_apple_xcode.cmake b/build_files/cmake/platform/platform_apple_xcode.cmake
index 3a43ca317dd..7e6bd14ecc3 100644
--- a/build_files/cmake/platform/platform_apple_xcode.cmake
+++ b/build_files/cmake/platform/platform_apple_xcode.cmake
@@ -154,3 +154,11 @@ if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
add_definitions("-DMACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Xcode")
+ # Generate schemes in Blender.xcodeproj/xcshareddata/xcschemes/ early, at
+ # configuration time, not when Xcode is opened.
+ # This gets rid of "Manage schemes automatically" confirmation dialog that
+ # appears whenever CMake is run.
+ set(CMAKE_XCODE_GENERATE_SCHEME ON)
+endif()
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 007f77a583f..64e4b276610 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -149,8 +149,8 @@ include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
remove_cc_flag("/MDd" "/MD" "/Zi")
if(WITH_WINDOWS_PDB)
- set(PDB_INFO_OVERRIDE_FLAGS "/Z7")
- set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
+ set(PDB_INFO_OVERRIDE_FLAGS "/Z7")
+ set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
endif()
if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp
index c7155276a30..a83465620ab 100644
--- a/extern/audaspace/bindings/C/AUD_Special.cpp
+++ b/extern/audaspace/bindings/C/AUD_Special.cpp
@@ -270,7 +270,7 @@ AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int sampl
return length;
}
-AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate)
+AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data)
{
try
{
@@ -280,7 +280,7 @@ AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned i
std::shared_ptr<IReader> reader = f->createQualityReader();
reader->seek(start);
std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, convCToDSpec(specs), static_cast<Container>(format), static_cast<Codec>(codec), bitrate);
- FileWriter::writeReader(reader, writer, length, buffersize);
+ FileWriter::writeReader(reader, writer, length, buffersize, callback, data);
return nullptr;
}
@@ -290,7 +290,7 @@ AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned i
}
}
-AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate)
+AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data)
{
try
{
@@ -326,7 +326,7 @@ AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start
std::shared_ptr<IReader> reader = f->createQualityReader();
reader->seek(start);
- FileWriter::writeReader(reader, writers, length, buffersize);
+ FileWriter::writeReader(reader, writers, length, buffersize, callback, data);
return nullptr;
}
diff --git a/extern/audaspace/bindings/C/AUD_Special.h b/extern/audaspace/bindings/C/AUD_Special.h
index 9faf9e4ee74..ce51fa2e04e 100644
--- a/extern/audaspace/bindings/C/AUD_Special.h
+++ b/extern/audaspace/bindings/C/AUD_Special.h
@@ -68,12 +68,15 @@ extern AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, in
* \param format The file's container format.
* \param codec The codec used for encoding the audio data.
* \param bitrate The bitrate for encoding.
+ * \param callback A callback function that is called periodically during mixdown, reporting progress if length > 0. Can be NULL.
+ * \param data Pass through parameter that is passed to the callback.
* \return An error message or NULL in case of success.
*/
extern AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length,
unsigned int buffersize, const char* filename,
AUD_DeviceSpecs specs, AUD_Container format,
- AUD_Codec codec, unsigned int bitrate);
+ AUD_Codec codec, unsigned int bitrate,
+ void(*callback)(float, void*), void* data);
/**
* Mixes a sound down into multiple files.
@@ -86,12 +89,15 @@ extern AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, uns
* \param format The file's container format.
* \param codec The codec used for encoding the audio data.
* \param bitrate The bitrate for encoding.
+ * \param callback A callback function that is called periodically during mixdown, reporting progress if length > 0. Can be NULL.
+ * \param data Pass through parameter that is passed to the callback.
* \return An error message or NULL in case of success.
*/
extern AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length,
unsigned int buffersize, const char* filename,
AUD_DeviceSpecs specs, AUD_Container format,
- AUD_Codec codec, unsigned int bitrate);
+ AUD_Codec codec, unsigned int bitrate,
+ void(*callback)(float, void*), void* data);
/**
* Opens a read device and prepares it for mixdown of the sound scene.
diff --git a/extern/audaspace/include/file/FileWriter.h b/extern/audaspace/include/file/FileWriter.h
index dac842f2a8f..13619d4de71 100644
--- a/extern/audaspace/include/file/FileWriter.h
+++ b/extern/audaspace/include/file/FileWriter.h
@@ -63,7 +63,7 @@ public:
* \param length How many samples should be transferred.
* \param buffersize How many samples should be transferred at once.
*/
- static void writeReader(std::shared_ptr<IReader> reader, std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize);
+ static void writeReader(std::shared_ptr<IReader> reader, std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, void(*callback)(float, void*) = nullptr, void* data = nullptr);
/**
* Writes a reader to several writers.
@@ -72,7 +72,7 @@ public:
* \param length How many samples should be transferred.
* \param buffersize How many samples should be transferred at once.
*/
- static void writeReader(std::shared_ptr<IReader> reader, std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned int buffersize);
+ static void writeReader(std::shared_ptr<IReader> reader, std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned int buffersize, void(*callback)(float, void*) = nullptr, void* data = nullptr);
};
AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/file/FileWriter.cpp b/extern/audaspace/src/file/FileWriter.cpp
index a6bb0f0049a..b28bbc5329d 100644
--- a/extern/audaspace/src/file/FileWriter.cpp
+++ b/extern/audaspace/src/file/FileWriter.cpp
@@ -27,7 +27,7 @@ std::shared_ptr<IWriter> FileWriter::createWriter(std::string filename,DeviceSpe
return FileManager::createWriter(filename, specs, format, codec, bitrate);
}
-void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize)
+void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, void(*callback)(float, void*), void* data)
{
Buffer buffer(buffersize * AUD_SAMPLE_SIZE(writer->getSpecs()));
sample_t* buf = buffer.getBuffer();
@@ -53,10 +53,18 @@ void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::shared_ptr<IW
}
writer->write(len, buf);
+
+ if(callback)
+ {
+ float progress = -1;
+ if(length > 0)
+ progress = pos / float(length);
+ callback(progress, data);
+ }
}
}
-void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned int buffersize)
+void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned int buffersize, void(*callback)(float, void*), void* data)
{
Buffer buffer(buffersize * AUD_SAMPLE_SIZE(reader->getSpecs()));
Buffer buffer2(buffersize * sizeof(sample_t));
@@ -89,6 +97,14 @@ void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::vector<std::s
writers[channel]->write(len, buf2);
}
+
+ if(callback)
+ {
+ float progress = -1;
+ if(length > 0)
+ progress = pos / float(length);
+ callback(progress, data);
+ }
}
}
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h
index 389bd62ba68..f12661b3095 100644
--- a/intern/cycles/kernel/closure/bsdf_hair_principled.h
+++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h
@@ -124,8 +124,8 @@ ccl_device_inline float bessel_I0(float x)
ccl_device_inline float log_bessel_I0(float x)
{
if (x > 12.0f) {
- /* log(1/x) == -log(x) iff x > 0.
- * This is only used with positive cosines */
+ /* log(1/x) == -log(x) if x > 0.
+ * This is only used with positive cosines. */
return x + 0.5f * (1.f / (8.0f * x) - M_LN_2PI_F - logf(x));
}
else {
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index cf7a06bf3e5..b6b83f2a47d 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -439,7 +439,6 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
GHOST_ActivateWindowDrawingContext(lw->win);
GPU_context_active_set(lw->gpu_context);
- immActivate();
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index c05bda030ad..71d3c512306 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -165,7 +165,7 @@ extern void (*MEM_set_error_callback)(void (*func)(const char *));
/**
* Are the start/end block markers still correct ?
*
- * @retval true for correct memory, false for corrupted memory. */
+ * \retval true for correct memory, false for corrupted memory. */
extern bool (*MEM_consistency_check)(void);
/** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index f8562241ef9..a8c8b212ecf 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -40,8 +40,10 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.sndparticle_potential_min_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-wavecrest"),
("bpy.types.fluiddomainsettings.sndparticle_potential_max_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-energy"),
("bpy.types.fluiddomainsettings.sndparticle_potential_min_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-energy"),
+ ("bpy.types.rigidbodyconstraint.rigidbodyconstraint.use_breaking*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-rigidbodyconstraint-use-breaking"),
("bpy.types.fluiddomainsettings.sndparticle_sampling_trappedair*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-trappedair"),
("bpy.types.fluiddomainsettings.sndparticle_sampling_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-wavecrest"),
+ ("bpy.types.rigidbodyconstraint.use_override_solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-use-override-solver-iterations"),
("bpy.types.toolsettings.use_transform_correct_face_attributes*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-transform-correct-face-attributes"),
("bpy.types.toolsettings.use_transform_correct_keep_connected*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-transform-correct-keep-connected"),
("bpy.types.fluiddomainsettings.sndparticle_potential_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-radius"),
@@ -59,8 +61,8 @@ url_manual_mapping = (
("bpy.types.brushgpencilsettings.use_settings_stabilizer*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-settings-stabilizer"),
("bpy.types.fluiddomainsettings.use_collision_border_top*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-top"),
("bpy.types.gpencilsculptsettings.use_multiframe_falloff*", "grease_pencil/multiframe.html#bpy-types-gpencilsculptsettings-use-multiframe-falloff"),
- ("bpy.types.rendersettings_simplify_gpencil_remove_lines*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-remove-lines"),
- ("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/editing/transform/control/options.html#bpy-types-toolsettings-use-transform-pivot-point-align"),
+ ("bpy.types.rendersettings.simplify_gpencil_antialiasing*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-antialiasing"),
+ ("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-pivot-point-align"),
("bpy.types.brush.show_multiplane_scrape_planes_preview*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-show-multiplane-scrape-planes-preview"),
("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"),
("bpy.types.fluiddomainsettings.sndparticle_bubble_drag*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-bubble-drag"),
@@ -87,6 +89,7 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_simplification*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/simplification.html#bpy-types-linestylegeometrymodifier-simplification"),
("bpy.types.materialgpencilstyle.use_overlap_strokes*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-use-overlap-strokes"),
("bpy.types.toolsettings.use_gpencil_weight_data_add*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-weight-data-add"),
+ ("bpy.types.view3doverlay.texture_paint_mode_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-texture-paint-mode-opacity"),
("bpy.types.brush.surface_smooth_shape_preservation*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-shape-preservation"),
("bpy.types.cyclesrendersettings.camera_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-camera-cull-margin"),
("bpy.types.fluiddomainsettings.export_manta_script*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-export-manta-script"),
@@ -100,6 +103,7 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"),
("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"),
("bpy.types.rendersettings.use_high_quality_normals*", "render/eevee/render_settings/performance.html#bpy-types-rendersettings-use-high-quality-normals"),
+ ("bpy.types.view3doverlay.vertex_paint_mode_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-vertex-paint-mode-opacity"),
("bpy.ops.view3d.edit_mesh_extrude_individual_move*", "modeling/meshes/editing/face/extrude_faces.html#bpy-ops-view3d-edit-mesh-extrude-individual-move"),
("bpy.ops.view3d.edit_mesh_extrude_manifold_normal*", "modeling/meshes/tools/extrude_manifold.html#bpy-ops-view3d-edit-mesh-extrude-manifold-normal"),
("bpy.types.cyclesrendersettings.use_distance_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-distance-cull"),
@@ -119,11 +123,13 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_spatialnoise*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/spatial_noise.html#bpy-types-linestylegeometrymodifier-spatialnoise"),
("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/parameter_editor/line_style/modifiers/thickness/calligraphy.html#bpy-types-linestylethicknessmodifier-calligraphy"),
("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"),
+ ("bpy.types.rigidbodyconstraint.breaking_threshold*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-breaking-threshold"),
("bpy.types.spacedopesheeteditor.show_pose_markers*", "animation/markers.html#bpy-types-spacedopesheeteditor-show-pose-markers"),
("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"),
("bpy.types.toolsettings.use_snap_backface_culling*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-backface-culling"),
- ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/editing/transform/control/options.html#bpy-types-toolsettings-use-transform-data-origin"),
+ ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-data-origin"),
("bpy.types.view3doverlay.sculpt_mode_mask_opacity*", "sculpt_paint/sculpting/hide_mask.html#bpy-types-view3doverlay-sculpt-mode-mask-opacity"),
+ ("bpy.ops.outliner.collection_indirect_only_clear*", "render/layers/layers.html#bpy-ops-outliner-collection-indirect-only-clear"),
("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-max-subdivisions"),
("bpy.types.fluiddomainsettings.axis_slice_method*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-axis-slice-method"),
("bpy.types.fluiddomainsettings.cache_data_format*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-data-format"),
@@ -141,7 +147,7 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_2dtransform*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/2d_transform.html#bpy-types-linestylegeometrymodifier-2dtransform"),
("bpy.types.linestylegeometrymodifier_beziercurve*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/bezier_curve.html#bpy-types-linestylegeometrymodifier-beziercurve"),
("bpy.types.particlesettings.use_parent_particles*", "physics/particles/emitter/render.html#bpy-types-particlesettings-use-parent-particles"),
- ("bpy.types.rendersettings_simplify_gpencil_blend*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-blend"),
+ ("bpy.types.rigidbodyconstraint.solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-solver-iterations"),
("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"),
("bpy.types.cyclesrendersettings.use_camera_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-camera-cull"),
("bpy.types.fluiddomainsettings.guide_vel_factor*", "physics/fluid/type/domain/guides.html#bpy-types-fluiddomainsettings-guide-vel-factor"),
@@ -149,6 +155,7 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
("bpy.types.toolsettings.use_gpencil_draw_onback*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-onback"),
+ ("bpy.ops.outliner.collection_indirect_only_set*", "render/layers/layers.html#bpy-ops-outliner-collection-indirect-only-set"),
("bpy.ops.sequencer.deinterlace_selected_movies*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-deinterlace-selected-movies"),
("bpy.types.brush.surface_smooth_current_vertex*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-current-vertex"),
("bpy.types.brush.use_multiplane_scrape_dynamic*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-use-multiplane-scrape-dynamic"),
@@ -227,9 +234,12 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.volume_density*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-volume-density"),
("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-show-stroke"),
("bpy.types.posebone.use_ik_rotation_control*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-use-ik-rotation-control"),
+ ("bpy.types.scenegpencil.antialias_threshold*", "render/cycles/render_settings/grease_pencil.html#bpy-types-scenegpencil-antialias-threshold"),
("bpy.types.spaceview3d.show_object_viewport*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-viewport"),
("bpy.ops.constraint.disable_keep_transform*", "animation/constraints/interface/common.html#bpy-ops-constraint-disable-keep-transform"),
("bpy.ops.object.vertex_group_normalize_all*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-normalize-all"),
+ ("bpy.ops.outliner.collection_exclude_clear*", "render/layers/layers.html#bpy-ops-outliner-collection-exclude-clear"),
+ ("bpy.ops.outliner.collection_holdout_clear*", "render/layers/layers.html#bpy-ops-outliner-collection-holdout-clear"),
("bpy.ops.sculpt.face_set_change_visibility*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-face-set-change-visibility"),
("bpy.ops.sculpt.face_sets_randomize_colors*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-face-sets-randomize-colors"),
("bpy.types.brush.disconnected_distance_max*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-disconnected-distance-max"),
@@ -261,6 +271,8 @@ url_manual_mapping = (
("bpy.ops.gpencil.active_frames_delete_all*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-active-frames-delete-all"),
("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-merge-by-distance"),
("bpy.ops.object.anim_transforms_to_deltas*", "scene_layout/object/editing/apply.html#bpy-ops-object-anim-transforms-to-deltas"),
+ ("bpy.ops.preferences.app_template_install*", "advanced/app_templates.html#bpy-ops-preferences-app-template-install"),
+ ("bpy.types.actionposemarkers.active_index*", "animation/armatures/properties/pose_library.html#bpy-types-actionposemarkers-active-index"),
("bpy.types.brushgpencilsettings.uv_random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-uv-random"),
("bpy.types.clothsettings.internal_tension*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-tension"),
("bpy.types.compositornodeplanetrackdeform*", "compositing/types/distort/plane_track_deform.html#bpy-types-compositornodeplanetrackdeform"),
@@ -286,9 +298,13 @@ url_manual_mapping = (
("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"),
("bpy.types.spaceview3d.show_object_select*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-select"),
("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"),
+ ("bpy.ops.armature.rigify_add_bone_groups*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-add-bone-groups"),
("bpy.ops.object.assign_property_defaults*", "animation/armatures/posing/editing/apply.html#bpy-ops-object-assign-property-defaults"),
("bpy.ops.object.vertex_group_limit_total*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-limit-total"),
("bpy.ops.object.vertex_group_remove_from*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-remove-from"),
+ ("bpy.ops.outliner.collection_exclude_set*", "render/layers/layers.html#bpy-ops-outliner-collection-exclude-set"),
+ ("bpy.ops.outliner.collection_holdout_set*", "render/layers/layers.html#bpy-ops-outliner-collection-holdout-set"),
+ ("bpy.ops.preferences.reset_default_theme*", "editors/preferences/themes.html#bpy-ops-preferences-reset-default-theme"),
("bpy.types.animdata.action_extrapolation*", "editors/nla/properties_modifiers.html#bpy-types-animdata-action-extrapolation"),
("bpy.types.brush.multiplane_scrape_angle*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-multiplane-scrape-angle"),
("bpy.types.clothsettings.internal_spring*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-spring"),
@@ -304,7 +320,10 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.temperature*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-temperature"),
("bpy.types.fluidflowsettings.use_texture*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-texture"),
("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
+ ("bpy.types.layercollection.hide_viewport*", "editors/outliner.html#bpy-types-layercollection-hide-viewport"),
+ ("bpy.types.layercollection.indirect_only*", "editors/outliner.html#bpy-types-layercollection-indirect-only"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
+ ("bpy.types.rigidbodyconstraint.use_limit*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-use-limit"),
("bpy.types.sceneeevee.taa_render_samples*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-taa-render-samples"),
("bpy.types.spacetexteditor.margin_column*", "editors/text_editor.html#bpy-types-spacetexteditor-margin-column"),
("bpy.types.spacetexteditor.use_find_wrap*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-wrap"),
@@ -329,6 +348,8 @@ url_manual_mapping = (
("bpy.types.shadernodevectordisplacement*", "render/shader_nodes/vector/vector_displacement.html#bpy-types-shadernodevectordisplacement"),
("bpy.types.spacegrapheditor.show_cursor*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-show-cursor"),
("bpy.types.spaceimageeditor.show_repeat*", "editors/image/view_tab.html#bpy-types-spaceimageeditor-show-repeat"),
+ ("bpy.types.spacepreferences.filter_text*", "editors/preferences/keymap.html#bpy-types-spacepreferences-filter-text"),
+ ("bpy.types.spacepreferences.filter_type*", "editors/preferences/keymap.html#bpy-types-spacepreferences-filter-type"),
("bpy.types.spacetexteditor.replace_text*", "editors/text_editor.html#bpy-types-spacetexteditor-replace-text"),
("bpy.types.spacetexteditor.use_find_all*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-all"),
("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"),
@@ -352,6 +373,9 @@ url_manual_mapping = (
("bpy.types.particlesettingstextureslot*", "physics/particles/texture_influence.html#bpy-types-particlesettingstextureslot"),
("bpy.types.posebone.ik_rotation_weight*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-ik-rotation-weight"),
("bpy.types.regionview3d.show_sync_view*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-show-sync-view"),
+ ("bpy.types.rigidbodyconstraint.enabled*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-enabled"),
+ ("bpy.types.rigidbodyconstraint.object1*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-object1"),
+ ("bpy.types.rigidbodyconstraint.object2*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-object2"),
("bpy.types.sceneeevee.volumetric_light*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric-light"),
("bpy.types.sculpt.symmetrize_direction*", "sculpt_paint/sculpting/tool_settings/symmetry.html#bpy-types-sculpt-symmetrize-direction"),
("bpy.types.sequenceeditor.show_overlay*", "video_editing/preview/properties.html#bpy-types-sequenceeditor-show-overlay"),
@@ -401,6 +425,7 @@ url_manual_mapping = (
("bpy.ops.pose.visual_transform_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-visual-transform-apply"),
("bpy.ops.sequencer.view_ghost_border*", "video_editing/preview/properties.html#bpy-ops-sequencer-view-ghost-border"),
("bpy.types.animdata.action_influence*", "editors/nla/properties_modifiers.html#bpy-types-animdata-action-influence"),
+ ("bpy.types.armature.layers_protected*", "animation/armatures/properties/skeleton.html#bpy-types-armature-layers-protected"),
("bpy.types.brush.crease_pinch_factor*", "sculpt_paint/sculpting/tools/snake_hook.html#bpy-types-brush-crease-pinch-factor"),
("bpy.types.brush.elastic_deform_type*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-type"),
("bpy.types.brush.use_primary_overlay*", "sculpt_paint/brush/cursor.html#bpy-types-brush-use-primary-overlay"),
@@ -420,6 +445,7 @@ url_manual_mapping = (
("bpy.types.object.empty_display_type*", "modeling/empties.html#bpy-types-object-empty-display-type"),
("bpy.types.regionview3d.use_box_clip*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-use-box-clip"),
("bpy.types.rendersettings.use_border*", "render/output/settings.html#bpy-types-rendersettings-use-border"),
+ ("bpy.types.rigidbodyconstraint.limit*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-limit"),
("bpy.types.scene.audio_doppler_speed*", "scene_layout/scene/properties.html#bpy-types-scene-audio-doppler-speed"),
("bpy.types.sceneeevee.bokeh_max_size*", "render/eevee/render_settings/depth_of_field.html#bpy-types-sceneeevee-bokeh-max-size"),
("bpy.types.shadernodebsdfanisotropic*", "render/shader_nodes/shader/anisotropic.html#bpy-types-shadernodebsdfanisotropic"),
@@ -447,6 +473,7 @@ url_manual_mapping = (
("bpy.ops.object.vertex_group_remove*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-remove"),
("bpy.ops.object.vertex_group_smooth*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-smooth"),
("bpy.ops.pose.user_transforms_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-user-transforms-clear"),
+ ("bpy.ops.poselib.browse_interactive*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-browse-interactive"),
("bpy.ops.sculpt.set_persistent_base*", "sculpt_paint/sculpting/tools/layer.html#bpy-ops-sculpt-set-persistent-base"),
("bpy.ops.sequencer.crossfade_sounds*", "video_editing/sequencer/strips/transitions/cross.html#bpy-ops-sequencer-crossfade-sounds"),
("bpy.ops.sequencer.export_subtitles*", "video_editing/preview/introduction.html#bpy-ops-sequencer-export-subtitles"),
@@ -493,11 +520,13 @@ url_manual_mapping = (
("bpy.ops.mesh.shortest_path_select*", "modeling/meshes/selecting/linked.html#bpy-ops-mesh-shortest-path-select"),
("bpy.ops.mesh.vert_connect_concave*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-vert-connect-concave"),
("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"),
+ ("bpy.ops.preferences.theme_install*", "editors/preferences/themes.html#bpy-ops-preferences-theme-install"),
("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-set-pivot-position"),
("bpy.ops.sequencer.reassign_inputs*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-reassign-inputs"),
("bpy.ops.view3d.view_center_camera*", "editors/3dview/navigate/camera_view.html#bpy-ops-view3d-view-center-camera"),
("bpy.types.armaturegpencilmodifier*", "grease_pencil/modifiers/deform/armature.html#bpy-types-armaturegpencilmodifier"),
+ ("bpy.types.brush.slide_deform_type*", "sculpt_paint/sculpting/tools/slide_relax.html#bpy-types-brush-slide-deform-type"),
("bpy.types.camera.show_composition*", "render/cameras.html#bpy-types-camera-show-composition"),
("bpy.types.compositornodealphaover*", "compositing/types/color/alpha_over.html#bpy-types-compositornodealphaover"),
("bpy.types.compositornodebokehblur*", "compositing/types/filter/bokeh_blur.html#bpy-types-compositornodebokehblur"),
@@ -519,6 +548,7 @@ url_manual_mapping = (
("bpy.types.gpencilsculptguide.type*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide-type"),
("bpy.types.laplaciandeformmodifier*", "modeling/modifiers/deform/laplacian_deform.html#bpy-types-laplaciandeformmodifier"),
("bpy.types.laplaciansmoothmodifier*", "modeling/modifiers/deform/laplacian_smooth.html#bpy-types-laplaciansmoothmodifier"),
+ ("bpy.types.layercollection.holdout*", "editors/outliner.html#bpy-types-layercollection-holdout"),
("bpy.types.limitdistanceconstraint*", "animation/constraints/transform/limit_distance.html#bpy-types-limitdistanceconstraint"),
("bpy.types.limitlocationconstraint*", "animation/constraints/transform/limit_location.html#bpy-types-limitlocationconstraint"),
("bpy.types.limitrotationconstraint*", "animation/constraints/transform/limit_rotation.html#bpy-types-limitrotationconstraint"),
@@ -534,6 +564,7 @@ url_manual_mapping = (
("bpy.types.toolsettings.annotation*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation"),
("bpy.types.vertexweightmixmodifier*", "modeling/modifiers/modify/weight_mix.html#bpy-types-vertexweightmixmodifier"),
("bpy.types.viewlayer.use_freestyle*", "render/freestyle/view_layer.html#bpy-types-viewlayer-use-freestyle"),
+ ("bpy.ops.armature.armature_layers*", "animation/armatures/bones/editing/change_layers.html#bpy-ops-armature-armature-layers"),
("bpy.ops.gpencil.frame_clean_fill*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-fill"),
("bpy.ops.gpencil.stroke_subdivide*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-subdivide"),
("bpy.ops.graph.interpolation_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-interpolation-type"),
@@ -553,6 +584,7 @@ url_manual_mapping = (
("bpy.ops.screen.spacedata_cleanup*", "advanced/operators.html#bpy-ops-screen-spacedata-cleanup"),
("bpy.ops.sequencer.duplicate_move*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-duplicate-move"),
("bpy.ops.uv.average_islands_scale*", "modeling/meshes/uv/editing.html#bpy-ops-uv-average-islands-scale"),
+ ("bpy.types.armature.pose_position*", "animation/armatures/properties/skeleton.html#bpy-types-armature-pose-position"),
("bpy.types.brightcontrastmodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-brightcontrastmodifier"),
("bpy.types.brush.cursor_color_add*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-color-add"),
("bpy.types.brush.pose_deform_type*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-pose-deform-type"),
@@ -560,6 +592,7 @@ url_manual_mapping = (
("bpy.types.brush.pose_origin_type*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-pose-origin-type"),
("bpy.types.camerasolverconstraint*", "animation/constraints/motion_tracking/camera_solver.html#bpy-types-camerasolverconstraint"),
("bpy.types.clothcollisionsettings*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings"),
+ ("bpy.types.collection.hide_select*", "editors/outliner.html#bpy-types-collection-hide-select"),
("bpy.types.compositornodecurvergb*", "compositing/types/color/rgb_curves.html#bpy-types-compositornodecurvergb"),
("bpy.types.compositornodecurvevec*", "compositing/types/vector/vector_curves.html#bpy-types-compositornodecurvevec"),
("bpy.types.compositornodedisplace*", "compositing/types/distort/displace.html#bpy-types-compositornodedisplace"),
@@ -614,12 +647,15 @@ url_manual_mapping = (
("bpy.ops.object.vertex_group_fix*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-fix"),
("bpy.ops.paint.brush_colors_flip*", "sculpt_paint/texture_paint/tool_settings/brush_settings.html#bpy-ops-paint-brush-colors-flip"),
("bpy.ops.paint.weight_from_bones*", "sculpt_paint/weight_paint/editing.html#bpy-ops-paint-weight-from-bones"),
+ ("bpy.ops.poselib.action_sanitize*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-action-sanitize"),
+ ("bpy.ops.preferences.studiolight*", "editors/preferences/lights.html#bpy-ops-preferences-studiolight"),
("bpy.ops.scene.view_layer_remove*", "render/layers/layers.html#bpy-ops-scene-view-layer-remove"),
("bpy.ops.screen.screen_full_area*", "interface/window_system/areas.html#bpy-ops-screen-screen-full-area"),
("bpy.ops.sculpt.face_sets_create*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-face-sets-create"),
("bpy.ops.transform.rotate_normal*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-transform-rotate-normal"),
("bpy.ops.transform.shrink_fatten*", "modeling/meshes/editing/mesh/transform/shrink-fatten.html#bpy-ops-transform-shrink-fatten"),
("bpy.ops.transform.vertex_random*", "modeling/meshes/editing/mesh/transform/randomize.html#bpy-ops-transform-vertex-random"),
+ ("bpy.ops.uv.shortest_path_select*", "editors/uv/selecting.html#bpy-ops-uv-shortest-path-select"),
("bpy.ops.wm.operator_cheat_sheet*", "advanced/operators.html#bpy-ops-wm-operator-cheat-sheet"),
("bpy.ops.wm.previews_batch_clear*", "files/blend/previews.html#bpy-ops-wm-previews-batch-clear"),
("bpy.types.armature.use_mirror_x*", "animation/armatures/bones/tools/tool_settings.html#bpy-types-armature-use-mirror-x"),
@@ -748,6 +784,8 @@ url_manual_mapping = (
("bpy.ops.paint.mask_flood_fill*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-paint-mask-flood-fill"),
("bpy.ops.pose.quaternions_flip*", "animation/armatures/posing/editing/flip_quats.html#bpy-ops-pose-quaternions-flip"),
("bpy.ops.pose.transforms_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-transforms-clear"),
+ ("bpy.ops.preferences.copy_prev*", "editors/preferences/introduction.html#bpy-ops-preferences-copy-prev"),
+ ("bpy.ops.preferences.keyconfig*", "editors/preferences/keymap.html#bpy-ops-preferences-keyconfig"),
("bpy.ops.screen.repeat_history*", "interface/undo_redo.html#bpy-ops-screen-repeat-history"),
("bpy.ops.sculpt.face_sets_init*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-face-sets-init"),
("bpy.ops.sequencer.change_path*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-path"),
@@ -810,6 +848,7 @@ url_manual_mapping = (
("bpy.types.windowmanager.addon*", "editors/preferences/addons.html#bpy-types-windowmanager-addon"),
("bpy.ops.anim.keyframe_delete*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-delete"),
("bpy.ops.anim.keyframe_insert*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-insert"),
+ ("bpy.ops.armature.bone_layers*", "animation/armatures/bones/editing/change_layers.html#bpy-ops-armature-bone-layers"),
("bpy.ops.clip.detect_features*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-detect-features"),
("bpy.ops.console.autocomplete*", "editors/python_console.html#bpy-ops-console-autocomplete"),
("bpy.ops.curve.dissolve_verts*", "modeling/curves/editing/curve.html#bpy-ops-curve-dissolve-verts"),
@@ -831,6 +870,7 @@ url_manual_mapping = (
("bpy.ops.object.select_mirror*", "scene_layout/object/selecting.html#bpy-ops-object-select-mirror"),
("bpy.ops.object.select_random*", "scene_layout/object/selecting.html#bpy-ops-object-select-random"),
("bpy.ops.paint.add_simple_uvs*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-ops-paint-add-simple-uvs"),
+ ("bpy.ops.preferences.autoexec*", "editors/preferences/save_load.html#bpy-ops-preferences-autoexec"),
("bpy.ops.scene.view_layer_add*", "render/layers/layers.html#bpy-ops-scene-view-layer-add"),
("bpy.ops.sculpt.face_set_edit*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-face-set-edit"),
("bpy.ops.sequencer.gap_insert*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-gap-insert"),
@@ -868,6 +908,7 @@ url_manual_mapping = (
("bpy.types.nodeoutputfileslot*", "compositing/types/output/file.html#bpy-types-nodeoutputfileslot"),
("bpy.types.normaleditmodifier*", "modeling/modifiers/modify/normal_edit.html#bpy-types-normaleditmodifier"),
("bpy.types.object.empty_image*", "modeling/empties.html#bpy-types-object-empty-image"),
+ ("bpy.types.object.hide_render*", "editors/outliner.html#bpy-types-object-hide-render"),
("bpy.types.object.show_bounds*", "scene_layout/object/properties/display.html#bpy-types-object-show-bounds"),
("bpy.types.scene.audio_volume*", "scene_layout/scene/properties.html#bpy-types-scene-audio-volume"),
("bpy.types.shadernodebsdfhair*", "render/shader_nodes/shader/hair.html#bpy-types-shadernodebsdfhair"),
@@ -914,17 +955,21 @@ url_manual_mapping = (
("bpy.ops.mesh.remove_doubles*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-remove-doubles"),
("bpy.ops.mesh.select_similar*", "modeling/meshes/selecting/similar.html#bpy-ops-mesh-select-similar"),
("bpy.ops.mesh.smooth_normals*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-smooth-normals"),
+ ("bpy.ops.nla.action_pushdown*", "editors/nla/tracks.html#bpy-ops-nla-action-pushdown"),
("bpy.ops.nla.tweakmode_enter*", "editors/nla/editing.html#bpy-ops-nla-tweakmode-enter"),
("bpy.ops.object.parent_clear*", "scene_layout/object/editing/parent.html#bpy-ops-object-parent-clear"),
("bpy.ops.object.shade_smooth*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-smooth"),
("bpy.ops.object.voxel_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-voxel-remesh"),
("bpy.ops.pose.armature_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-armature-apply"),
+ ("bpy.ops.poselib.pose_remove*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-remove"),
+ ("bpy.ops.poselib.pose_rename*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-rename"),
+ ("bpy.ops.preferences.keyitem*", "editors/preferences/keymap.html#bpy-ops-preferences-keyitem"),
("bpy.ops.sequencer.swap_data*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-swap-data"),
("bpy.ops.transform.push_pull*", "modeling/meshes/editing/mesh/transform/push_pull.html#bpy-ops-transform-push-pull"),
("bpy.ops.transform.seq_slide*", "video_editing/sequencer/editing.html#bpy-ops-transform-seq-slide"),
- ("bpy.ops.transform.trackball*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-trackball"),
+ ("bpy.ops.transform.trackball*", "scene_layout/object/editing/transform/rotate.html#bpy-ops-transform-trackball"),
("bpy.ops.transform.transform*", "scene_layout/object/editing/transform/align_transform_orientation.html#bpy-ops-transform-transform"),
- ("bpy.ops.transform.translate*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-translate"),
+ ("bpy.ops.transform.translate*", "scene_layout/object/editing/transform/move.html#bpy-ops-transform-translate"),
("bpy.ops.uv.cylinder_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cylinder-project"),
("bpy.ops.uv.minimize_stretch*", "modeling/meshes/uv/editing.html#bpy-ops-uv-minimize-stretch"),
("bpy.types.alphaoversequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaoversequence"),
@@ -1002,6 +1047,7 @@ url_manual_mapping = (
("bpy.ops.object.select_less*", "scene_layout/object/selecting.html#bpy-ops-object-select-less"),
("bpy.ops.object.select_more*", "scene_layout/object/selecting.html#bpy-ops-object-select-more"),
("bpy.ops.object.track_clear*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-clear"),
+ ("bpy.ops.poselib.apply_pose*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-apply-pose"),
("bpy.ops.screen.repeat_last*", "interface/undo_redo.html#bpy-ops-screen-repeat-last"),
("bpy.ops.sculpt.mask_expand*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-sculpt-mask-expand"),
("bpy.ops.sculpt.mask_filter*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-sculpt-mask-filter"),
@@ -1009,6 +1055,7 @@ url_manual_mapping = (
("bpy.ops.view3d.clip_border*", "editors/3dview/navigate/regions.html#bpy-ops-view3d-clip-border"),
("bpy.ops.wm.previews_ensure*", "files/blend/previews.html#bpy-ops-wm-previews-ensure"),
("bpy.ops.wm.search_operator*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search-operator"),
+ ("bpy.opsuv.select_edge_ring*", "editors/uv/selecting.html#bpy-opsuv-select-edge-ring"),
("bpy.types.actionconstraint*", "animation/constraints/relationship/action.html#bpy-types-actionconstraint"),
("bpy.types.addonpreferences*", "editors/preferences/addons.html#bpy-types-addonpreferences"),
("bpy.types.armaturemodifier*", "modeling/modifiers/deform/armature.html#bpy-types-armaturemodifier"),
@@ -1044,7 +1091,7 @@ url_manual_mapping = (
("bpy.types.shadernodetexies*", "render/shader_nodes/textures/ies.html#bpy-types-shadernodetexies"),
("bpy.types.shadernodetexsky*", "render/shader_nodes/textures/sky.html#bpy-types-shadernodetexsky"),
("bpy.types.softbodymodifier*", "physics/soft_body/index.html#bpy-types-softbodymodifier"),
- ("bpy.types.softbodysettings*", "physics/soft_body/settings.html#bpy-types-softbodysettings"),
+ ("bpy.types.softbodysettings*", "physics/soft_body/settings/index.html#bpy-types-softbodysettings"),
("bpy.types.solidifymodifier*", "modeling/modifiers/generate/solidify.html#bpy-types-solidifymodifier"),
("bpy.types.spacegrapheditor*", "editors/graph_editor/index.html#bpy-types-spacegrapheditor"),
("bpy.types.spacepreferences*", "editors/preferences/index.html#bpy-types-spacepreferences"),
@@ -1078,6 +1125,7 @@ url_manual_mapping = (
("bpy.ops.object.proxy_make*", "files/linked_libraries/library_proxies.html#bpy-ops-object-proxy-make"),
("bpy.ops.object.select_all*", "scene_layout/object/selecting.html#bpy-ops-object-select-all"),
("bpy.ops.object.shade_flat*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-flat"),
+ ("bpy.ops.poselib.pose_move*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-pose-move"),
("bpy.ops.preferences.addon*", "editors/preferences/addons.html#bpy-ops-preferences-addon"),
("bpy.ops.scene.light_cache*", "render/eevee/render_settings/indirect_lighting.html#bpy-ops-scene-light-cache"),
("bpy.ops.screen.area_dupli*", "interface/window_system/areas.html#bpy-ops-screen-area-dupli"),
@@ -1086,6 +1134,7 @@ url_manual_mapping = (
("bpy.ops.uv.remove_doubles*", "modeling/meshes/uv/editing.html#bpy-ops-uv-remove-doubles"),
("bpy.ops.uv.sphere_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-sphere-project"),
("bpy.ops.wm.previews_clear*", "files/blend/previews.html#bpy-ops-wm-previews-clear"),
+ ("bpy.types.armature.layers*", "animation/armatures/properties/skeleton.html#bpy-types-armature-layers"),
("bpy.types.booleanmodifier*", "modeling/modifiers/generate/booleans.html#bpy-types-booleanmodifier"),
("bpy.types.brush.mask_tool*", "sculpt_paint/sculpting/tools/mask.html#bpy-types-brush-mask-tool"),
("bpy.types.constraint.mute*", "animation/constraints/interface/header.html#bpy-types-constraint-mute"),
@@ -1135,14 +1184,15 @@ url_manual_mapping = (
("bpy.ops.object.hide_view*", "scene_layout/object/editing/show_hide.html#bpy-ops-object-hide-view"),
("bpy.ops.object.track_set*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-set"),
("bpy.ops.pose.scale_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-scale-clear"),
+ ("bpy.ops.poselib.pose_add*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-add"),
("bpy.ops.scene.view_layer*", "render/layers/layers.html#bpy-ops-scene-view-layer"),
("bpy.ops.sequencer.delete*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-delete"),
("bpy.ops.sequencer.reload*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-reload"),
("bpy.ops.sequencer.unlock*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-unlock"),
("bpy.ops.sequencer.unmute*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-unmute"),
("bpy.ops.transform.mirror*", "scene_layout/object/editing/mirror.html#bpy-ops-transform-mirror"),
- ("bpy.ops.transform.resize*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-resize"),
- ("bpy.ops.transform.rotate*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-rotate"),
+ ("bpy.ops.transform.resize*", "scene_layout/object/editing/transform/scale.html#bpy-ops-transform-resize"),
+ ("bpy.ops.transform.rotate*", "scene_layout/object/editing/transform/rotate.html#bpy-ops-transform-rotate"),
("bpy.ops.uv.lightmap_pack*", "modeling/meshes/editing/uv.html#bpy-ops-uv-lightmap-pack"),
("bpy.ops.uv.smart_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-smart-project"),
("bpy.ops.uv.snap_selected*", "modeling/meshes/uv/editing.html#bpy-ops-uv-snap-selected"),
@@ -1326,6 +1376,7 @@ url_manual_mapping = (
("bpy.ops.nla.move_down*", "editors/nla/editing.html#bpy-ops-nla-move-down"),
("bpy.ops.object.*clear*", "scene_layout/object/editing/clear.html#bpy-ops-object-clear"),
("bpy.ops.object.delete*", "scene_layout/object/editing/delete.html#bpy-ops-object-delete"),
+ ("bpy.ops.render.opengl*", "editors/3dview/viewport_render.html#bpy-ops-render-opengl"),
("bpy.ops.screen.header*", "interface/window_system/regions.html#bpy-ops-screen-header"),
("bpy.ops.script.reload*", "advanced/operators.html#bpy-ops-script-reload"),
("bpy.ops.view3d.select*", "editors/3dview/selecting.html#bpy-ops-view3d-select"),
@@ -1389,6 +1440,7 @@ url_manual_mapping = (
("bpy.ops.object.hook*", "modeling/meshes/editing/vertex/hooks.html#bpy-ops-object-hook"),
("bpy.ops.object.join*", "scene_layout/object/editing/join.html#bpy-ops-object-join"),
("bpy.ops.object.text*", "modeling/texts/index.html#bpy-ops-object-text"),
+ ("bpy.ops.preferences*", "editors/preferences/index.html#bpy-ops-preferences"),
("bpy.ops.uv.rip_move*", "modeling/meshes/uv/tools/rip.html#bpy-ops-uv-rip-move"),
("bpy.ops.view3d.snap*", "scene_layout/object/editing/snap.html#bpy-ops-view3d-snap"),
("bpy.types.*texspace*", "modeling/meshes/uv/uv_texture_spaces.html#bpy-types-texspace"),
@@ -1494,7 +1546,7 @@ url_manual_mapping = (
("bpy.ops.ed.undo*", "interface/undo_redo.html#bpy-ops-ed-undo"),
("bpy.ops.gpencil*", "grease_pencil/index.html#bpy-ops-gpencil"),
("bpy.ops.lattice*", "animation/lattice.html#bpy-ops-lattice"),
- ("bpy.ops.poselib*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib"),
+ ("bpy.ops.poselib*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib"),
("bpy.ops.ptcache*", "physics/baking.html#bpy-ops-ptcache"),
("bpy.ops.surface*", "modeling/surfaces/index.html#bpy-ops-surface"),
("bpy.ops.texture*", "render/materials/legacy_textures/index.html#bpy-ops-texture"),
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 9062e42f015..8ff0c55e7a0 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -6349,7 +6349,6 @@ def km_3d_view_tool_sculpt_box_face_set(params):
]},
)
-
def km_3d_view_tool_sculpt_lasso_face_set(params):
return (
"3D View Tool: Sculpt, Lasso Face Set",
@@ -6359,6 +6358,26 @@ def km_3d_view_tool_sculpt_lasso_face_set(params):
None),
]},
)
+
+def km_3d_view_tool_sculpt_box_trim(params):
+ return (
+ "3D View Tool: Sculpt, Box Trim",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("sculpt.trim_box_gesture", {"type": params.tool_tweak, "value": 'ANY'},
+ None),
+ ]},
+ )
+
+def km_3d_view_tool_sculpt_lasso_trim(params):
+ return (
+ "3D View Tool: Sculpt, Lasso Trim",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("sculpt.trim_lasso_gesture", {"type": params.tool_tweak, "value": 'ANY'},
+ None),
+ ]},
+ )
def km_3d_view_tool_sculpt_mesh_filter(params):
return (
@@ -6956,6 +6975,8 @@ def generate_keymaps(params=None):
km_3d_view_tool_sculpt_lasso_mask(params),
km_3d_view_tool_sculpt_box_face_set(params),
km_3d_view_tool_sculpt_lasso_face_set(params),
+ km_3d_view_tool_sculpt_box_trim(params),
+ km_3d_view_tool_sculpt_lasso_trim(params),
km_3d_view_tool_sculpt_mesh_filter(params),
km_3d_view_tool_sculpt_cloth_filter(params),
km_3d_view_tool_sculpt_color_filter(params),
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index df4793cab19..8618c201312 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -92,6 +92,7 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
subcol.prop(unit, "length_unit", text="Length")
subcol.prop(unit, "mass_unit", text="Mass")
subcol.prop(unit, "time_unit", text="Time")
+ subcol.prop(unit, "temperature_unit", text="Temperature")
class SceneKeyingSetsPanel:
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 1a9244a3051..68b5f8acd38 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -230,34 +230,37 @@ class TimelinePanelButtons:
class TIME_PT_playback(TimelinePanelButtons, Panel):
bl_label = "Playback"
bl_region_type = 'HEADER'
+ bl_ui_units_x = 11
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
screen = context.screen
scene = context.scene
- layout.prop(scene, "sync_mode", text="")
- layout.prop(scene, "use_audio_scrub")
- layout.prop(scene, "use_audio", text="Mute Audio")
-
- layout.prop(scene, "show_subframe", text="Subframes")
-
- layout.prop(scene, "lock_frame_selection_to_range", text="Limit Playback to Frame Range")
- layout.prop(screen, "use_follow", text="Follow Current Frame")
-
- layout.separator()
-
col = layout.column()
- col.label(text="Play Animation In:")
- layout.prop(screen, "use_play_top_left_3d_editor", text="Active Editor Only")
- layout.prop(screen, "use_play_3d_editors")
- layout.prop(screen, "use_play_animation_editors")
- layout.prop(screen, "use_play_properties_editors")
- layout.prop(screen, "use_play_image_editors")
- layout.prop(screen, "use_play_sequence_editors")
- layout.prop(screen, "use_play_node_editors")
- layout.prop(screen, "use_play_clip_editors")
+ col.prop(scene, "sync_mode", text="Audio")
+ col.prop(scene, "use_audio_scrub", text="Scrubbing")
+ col.prop(scene, "use_audio", text="Mute")
+
+ col = layout.column(heading="Playback")
+ col.prop(scene, "lock_frame_selection_to_range", text="Limit to Frame Range")
+ col.prop(screen, "use_follow", text="Follow Current Frame")
+
+ col = layout.column(heading="Play In")
+ col.prop(screen, "use_play_top_left_3d_editor", text="Active Editor")
+ col.prop(screen, "use_play_3d_editors", text="3D Viewport")
+ col.prop(screen, "use_play_animation_editors", text="Animation Editors")
+ col.prop(screen, "use_play_image_editors", text="Image Editor")
+ col.prop(screen, "use_play_properties_editors", text="Properties Editor")
+ col.prop(screen, "use_play_clip_editors", text="Movie Clip Editor")
+ col.prop(screen, "use_play_node_editors", text="Node Editors")
+ col.prop(screen, "use_play_sequence_editors", text="Video Sequencer")
+
+ col = layout.column(heading="Show")
+ col.prop(scene, "show_subframe", text="Subframes")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index c17b981a6b8..75dfd60b1d4 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1200,11 +1200,15 @@ class _defs_sculpt:
@staticmethod
def generate_from_brushes(context):
- if bpy.context.preferences.experimental.use_sculpt_vertex_colors:
- exclude_filter = {}
- else:
+ exclude_filter = {}
+ # Use 'bpy.context' instead of 'context' since it can be None.
+ prefs = bpy.context.preferences
+ if not prefs.experimental.use_sculpt_vertex_colors:
exclude_filter = {'PAINT', 'SMEAR'}
+ if not prefs.experimental.use_tools_missing_icons:
+ exclude_filter = {'PAINT', 'SMEAR', 'BOUNDARY', 'DISPLACEMENT_ERASER'}
+
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
@@ -1284,6 +1288,26 @@ class _defs_sculpt:
draw_settings=draw_settings,
)
+ @ToolDef.from_fn
+ def trim_box():
+ return dict(
+ idname="builtin.box_trim",
+ label="Box Trim",
+ icon="ops.sculpt.box_trim",
+ widget=None,
+ keymap=(),
+ )
+
+ @ToolDef.from_fn
+ def trim_lasso():
+ return dict(
+ idname="builtin.lasso_trim",
+ label="Lasso Trim",
+ icon="ops.sculpt.lasso_trim",
+ widget=None,
+ keymap=(),
+ )
+
@ToolDef.from_fn
def mesh_filter():
@@ -2627,11 +2651,35 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_sculpt.mask_border,
_defs_sculpt.mask_lasso,
),
- (
- _defs_sculpt.face_set_box,
- _defs_sculpt.face_set_lasso,
- ),
_defs_sculpt.hide_border,
+ lambda context: (
+ (_defs_sculpt.face_set_box,)
+ if context is None or (
+ context.preferences.view.show_developer_ui and
+ context.preferences.experimental.use_tools_missing_icons)
+ else ()
+ ),
+ lambda context: (
+ (_defs_sculpt.face_set_lasso,)
+ if context is None or (
+ context.preferences.view.show_developer_ui and
+ context.preferences.experimental.use_tools_missing_icons)
+ else ()
+ ),
+ lambda context: (
+ (_defs_sculpt.trim_box,)
+ if context is None or (
+ context.preferences.view.show_developer_ui and
+ context.preferences.experimental.use_tools_missing_icons)
+ else ()
+ ),
+ lambda context: (
+ (_defs_sculpt.trim_lasso,)
+ if context is None or (
+ context.preferences.view.show_developer_ui and
+ context.preferences.experimental.use_tools_missing_icons)
+ else ()
+ ),
None,
_defs_sculpt.mesh_filter,
_defs_sculpt.cloth_filter,
@@ -2639,7 +2687,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
(_defs_sculpt.color_filter,)
if context is None or (
context.preferences.view.show_developer_ui and
- context.preferences.experimental.use_sculpt_vertex_colors)
+ context.preferences.experimental.use_sculpt_vertex_colors and
+ context.preferences.experimental.use_tools_missing_icons)
else ()
),
None,
@@ -2647,11 +2696,18 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
(_defs_sculpt.mask_by_color,)
if context is None or (
context.preferences.view.show_developer_ui and
- context.preferences.experimental.use_sculpt_vertex_colors)
+ context.preferences.experimental.use_sculpt_vertex_colors and
+ context.preferences.experimental.use_tools_missing_icons)
else ()
),
None,
- _defs_sculpt.face_set_edit,
+ lambda context: (
+ (_defs_sculpt.face_set_edit,)
+ if context is None or (
+ context.preferences.view.show_developer_ui and
+ context.preferences.experimental.use_tools_missing_icons)
+ else ()
+ ),
None,
_defs_transform.translate,
_defs_transform.rotate,
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 9548de20752..506849fbee5 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2164,6 +2164,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
context, (
({"property": "use_new_particle_system"}, "T73324"),
({"property": "use_sculpt_vertex_colors"}, "T71947"),
+ ({"property": "use_tools_missing_icons"}, "T80331"),
),
)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index b44f2624702..91953c08936 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1089,10 +1089,7 @@ class VIEW3D_MT_uv_map(Menu):
def draw(self, context):
layout = self.layout
- tool_settings = context.tool_settings
-
layout.operator("uv.unwrap")
- layout.prop(tool_settings, "use_edge_path_live_unwrap")
layout.separator()
@@ -1385,7 +1382,7 @@ class VIEW3D_MT_select_object(Menu):
layout.separator()
- layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...")
+ layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type")
layout.operator("object.select_camera", text="Select Active Camera")
layout.operator("object.select_mirror", text="Mirror Selection")
layout.operator("object.select_random", text="Select Random")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 09744e44f35..6359426128f 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -212,6 +212,9 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
row.active = tool_settings.use_transform_correct_face_attributes
row.prop(tool_settings, "use_transform_correct_keep_connected")
+ row = layout.row(align=True, heading="UVs")
+ row.prop(tool_settings, "use_edge_path_live_unwrap")
+
row = layout.row(heading="Mirror")
sub = row.row(align=True)
sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
diff --git a/release/scripts/templates_py/ui_menu.py b/release/scripts/templates_py/ui_menu.py
index 36391a54f4e..7c19693485e 100644
--- a/release/scripts/templates_py/ui_menu.py
+++ b/release/scripts/templates_py/ui_menu.py
@@ -18,7 +18,7 @@ class CustomMenu(bpy.types.Menu):
# use an operator enum property to populate a sub-menu
layout.operator_menu_enum("object.select_by_type",
property="type",
- text="Select All by Type...",
+ text="Select All by Type",
)
# call another menu
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 773d3409905..8e74d5bba7c 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -46,7 +46,7 @@
#include "BLF_api.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_immediate.h"
#include "blf_internal.h"
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 7c5d0011465..8164d34f32b 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -83,7 +83,7 @@ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
bool BKE_pose_minmax(
struct Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select);
-int bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail);
+bool bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail);
struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name);
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 25360d4b3fa..d21fe5afa7e 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -414,11 +414,6 @@ void CustomData_from_bmesh_block(const struct CustomData *source,
void *src_block,
int dest_index);
-void CustomData_file_write_prepare(struct CustomData *data,
- struct CustomDataLayer **r_write_layers,
- struct CustomDataLayer *write_layers_buff,
- size_t write_layers_size);
-
/* query info over types */
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
@@ -574,8 +569,14 @@ void CustomData_data_transfer(const struct MeshPairRemap *me_remap,
const CustomDataTransferLayerMap *laymap);
/* .blend file I/O */
+void CustomData_blend_write_prepare(struct CustomData *data,
+ struct CustomDataLayer **r_write_layers,
+ struct CustomDataLayer *write_layers_buff,
+ size_t write_layers_size);
+
void CustomData_blend_write(struct BlendWriter *writer,
struct CustomData *data,
+ CustomDataLayer *layers,
int count,
CustomDataMask cddata_mask,
struct ID *id);
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 7e1a6e54ede..b2502031029 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -30,16 +30,24 @@
extern "C" {
#endif
-/* dl->type */
-#define DL_POLY 0
-#define DL_SEGM 1
-#define DL_SURF 2
-#define DL_INDEX3 4
-#define DL_INDEX4 5
-// #define DL_VERTCOL 6 // UNUSED
-#define DL_VERTS 7
-
-/* dl->flag */
+/** #DispList.type */
+enum {
+ /** A closed polygon (that can be filled). */
+ DL_POLY = 0,
+ /** An open polygon. */
+ DL_SEGM = 1,
+ /** A grid surface that respects #DL_CYCL_U & #DL_CYCL_V. */
+ DL_SURF = 2,
+ /** Triangles. */
+ DL_INDEX3 = 4,
+ /** Quads, with support for triangles (when values of the 3rd and 4th indices match). */
+ DL_INDEX4 = 5,
+ // DL_VERTCOL = 6, /* UNUSED */
+ /** Isolated points. */
+ DL_VERTS = 7,
+};
+
+/** #DispList.type */
enum {
/** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */
DL_CYCL_U = (1 << 0),
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index a797c5555ff..c4af9ab40e2 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -29,49 +29,49 @@ struct UnitSettings;
/* in all cases the value is assumed to be scaled by the user preference */
/* humanly readable representation of a value in units (used for button drawing) */
-size_t bUnit_AsString(
+size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
-size_t bUnit_AsString2(char *str,
- int len_max,
- double value,
- int prec,
- int type,
- const struct UnitSettings *settings,
- bool pad);
+size_t BKE_unit_value_as_string(char *str,
+ int len_max,
+ double value,
+ int prec,
+ int type,
+ const struct UnitSettings *settings,
+ bool pad);
/* replace units with values, used before python button evaluation */
-bool bUnit_ReplaceString(
+bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
/* return true if the string contains any valid unit for the given type */
-bool bUnit_ContainsUnit(const char *str, int type);
+bool BKE_unit_string_contains_unit(const char *str, int type);
-/* if user does not specify a unit, multiply with this value */
-double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int type);
+/* If user does not specify a unit, this converts it to the unit from the settings. */
+double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value);
/* make string keyboard-friendly: 10µm --> 10um */
-void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type);
+void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type);
/* the size of the unit used for this value (used for calculating the ckickstep) */
-double bUnit_ClosestScalar(double value, int system, int type);
+double BKE_unit_closest_scalar(double value, int system, int type);
/* base scale for these units */
-double bUnit_BaseScalar(int system, int type);
+double BKE_unit_base_scalar(int system, int type);
/* return true is the unit system exists */
-bool bUnit_IsValid(int system, int type);
+bool BKE_unit_is_valid(int system, int type);
/* loop over scales, could add names later */
// double bUnit_Iter(void **unit, char **name, int system, int type);
-void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len);
-int bUnit_GetBaseUnit(const void *usys_pt);
-int bUnit_GetBaseUnitOfType(int system, int type);
-const char *bUnit_GetName(const void *usys_pt, int index);
-const char *bUnit_GetNameDisplay(const void *usys_pt, int index);
-const char *bUnit_GetIdentifier(const void *usys_pt, int index);
-double bUnit_GetScaler(const void *usys_pt, int index);
-bool bUnit_IsSuppressed(const void *usys_pt, int index);
+void BKE_unit_system_get(int system, int type, const void **r_usys_pt, int *r_len);
+int BKE_unit_base_get(const void *usys_pt);
+int BKE_unit_base_of_type_get(int system, int type);
+const char *BKE_unit_name_get(const void *usys_pt, int index);
+const char *BKE_unit_display_name_get(const void *usys_pt, int index);
+const char *BKE_unit_identifier_get(const void *usys_pt, int index);
+double BKE_unit_scalar_get(const void *usys_pt, int index);
+bool BKE_unit_is_suppressed(const void *usys_pt, int index);
/* aligned with PropertyUnit */
enum {
@@ -86,7 +86,8 @@ enum {
B_UNIT_ACCELERATION = 8,
B_UNIT_CAMERA = 9,
B_UNIT_POWER = 10,
- B_UNIT_TYPE_TOT = 11,
+ B_UNIT_TEMPERATURE = 11,
+ B_UNIT_TYPE_TOT = 12,
};
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_inline.h b/source/blender/blenkernel/intern/CCGSubSurf_inline.h
index 8aa1fede57d..91a7129b433 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_inline.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_inline.h
@@ -213,15 +213,15 @@ BLI_INLINE void Normalize(float no[3])
/* Data layers mathematics. */
-BLI_INLINE int VertDataEqual(const float a[], const float b[], const CCGSubSurf *ss)
+BLI_INLINE bool VertDataEqual(const float a[], const float b[], const CCGSubSurf *ss)
{
int i;
for (i = 0; i < ss->meshIFC.numLayers; i++) {
if (a[i] != b[i]) {
- return 0;
+ return false;
}
}
- return 1;
+ return true;
}
BLI_INLINE void VertDataZero(float v[], const CCGSubSurf *ss)
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index 8fc9afd58f1..b723d39ca08 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -47,15 +47,15 @@ static int _edge_isBoundary(const CCGEdge *e)
return e->numFaces < 2;
}
-static int _vert_isBoundary(const CCGVert *v)
+static bool _vert_isBoundary(const CCGVert *v)
{
int i;
for (i = 0; i < v->numEdges; i++) {
if (_edge_isBoundary(v->edges[i])) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ)
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 3b73702cf0f..a653087f961 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -565,7 +565,7 @@ void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmatu
* unique names afterwards) strip_number: removes number extensions (TODO: not used)
* axis: the axis to name on
* head/tail: the head/tail co-ordinate of the bone on the specified axis */
-int bone_autoside_name(
+bool bone_autoside_name(
char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
{
unsigned int len;
@@ -574,7 +574,7 @@ int bone_autoside_name(
len = strlen(name);
if (len == 0) {
- return 0;
+ return false;
}
BLI_strncpy(basename, name, sizeof(basename));
@@ -689,9 +689,9 @@ int bone_autoside_name(
BLI_snprintf(name, MAXBONENAME, "%s.%s", basename, extension);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index e950e94655a..9f5e038fb82 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -93,9 +93,12 @@ bool BKE_copybuffer_read(Main *bmain_dst,
return false;
}
/* Here appending/linking starts. */
- Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
+ const int flag = 0;
+ struct LibraryLink_Params liblink_params;
+ BLO_library_link_params_init(&liblink_params, bmain_dst, flag);
+ Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL, NULL);
+ BLO_library_link_end(mainl, &bh, &liblink_params);
/* Mark all library linked objects to be updated. */
BKE_main_lib_objects_recalc_all(bmain_dst);
IMB_colormanagement_check_file_config(bmain_dst);
@@ -144,11 +147,13 @@ int BKE_copybuffer_paste(bContext *C,
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* here appending/linking starts */
- mainl = BLO_library_link_begin(bmain, &bh, libname);
+ struct LibraryLink_Params liblink_params;
+ BLO_library_link_params_init_with_context(&liblink_params, bmain, flag, scene, view_layer, v3d);
+ mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer, v3d);
+ BLO_library_link_end(mainl, &bh, &liblink_params);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index ee60bf79611..4ea8ae555e3 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -413,7 +413,7 @@ static void setup_app_blend_file_data(bContext *C,
}
}
-static int handle_subversion_warning(Main *main, ReportList *reports)
+static bool handle_subversion_warning(Main *main, ReportList *reports)
{
if (main->minversionfile > BLENDER_FILE_VERSION ||
(main->minversionfile == BLENDER_FILE_VERSION &&
@@ -425,7 +425,7 @@ static int handle_subversion_warning(Main *main, ReportList *reports)
main->minsubversionfile);
}
- return 1;
+ return true;
}
int BKE_blendfile_read(bContext *C,
@@ -443,7 +443,7 @@ int BKE_blendfile_read(bContext *C,
bfd = BLO_read_from_file(filepath, params->skip_flags, reports);
if (bfd) {
- if (0 == handle_subversion_warning(bfd->main, reports)) {
+ if (!handle_subversion_warning(bfd->main, reports)) {
BKE_main_free(bfd->main);
MEM_freeN(bfd);
bfd = NULL;
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a7324ffe738..78ce70a8448 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -68,18 +68,18 @@ typedef struct BoidValues {
float personal_space, jump_speed;
} BoidValues;
-static int apply_boid_rule(
+static bool apply_boid_rule(
BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
-static int rule_none(BoidRule *UNUSED(rule),
- BoidBrainData *UNUSED(data),
- BoidValues *UNUSED(val),
- ParticleData *UNUSED(pa))
+static bool rule_none(BoidRule *UNUSED(rule),
+ BoidBrainData *UNUSED(data),
+ BoidValues *UNUSED(val),
+ ParticleData *UNUSED(pa))
{
- return 0;
+ return false;
}
-static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+static bool rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
BoidSettings *boids = bbd->part->boids;
@@ -91,7 +91,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
EffectorData efd, cur_efd;
float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
float priority = 0.0f, len = 0.0f;
- int ret = 0;
+ bool ret = false;
int p = 0;
efd.index = cur_efd.index = &p;
@@ -207,16 +207,16 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
}
}
- ret = 1;
+ ret = true;
}
return ret;
}
-static int rule_avoid_collision(BoidRule *rule,
- BoidBrainData *bbd,
- BoidValues *val,
- ParticleData *pa)
+static bool rule_avoid_collision(BoidRule *rule,
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision *)rule;
@@ -228,7 +228,7 @@ static int rule_avoid_collision(BoidRule *rule,
float co1[3], vel1[3], co2[3], vel2[3];
float len, t, inp, t_min = 2.0f;
int n, neighbors = 0, nearest = 0;
- int ret = 0;
+ bool ret = 0;
// check deflector objects first
if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
@@ -288,7 +288,7 @@ static int rule_avoid_collision(BoidRule *rule,
bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);
- return 1;
+ return true;
}
}
@@ -413,10 +413,10 @@ static int rule_avoid_collision(BoidRule *rule,
return ret;
}
-static int rule_separate(BoidRule *UNUSED(rule),
- BoidBrainData *bbd,
- BoidValues *val,
- ParticleData *pa)
+static bool rule_separate(BoidRule *UNUSED(rule),
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
KDTreeNearest_3d *ptn = NULL;
ParticleTarget *pt;
@@ -424,7 +424,7 @@ static int rule_separate(BoidRule *UNUSED(rule),
float vec[3] = {0.0f, 0.0f, 0.0f};
int neighbors = BLI_kdtree_3d_range_search(
bbd->sim->psys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
- int ret = 0;
+ bool ret = false;
if (neighbors > 1 && ptn[1].dist != 0.0f) {
sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
@@ -453,7 +453,7 @@ static int rule_separate(BoidRule *UNUSED(rule),
add_v3_v3(bbd->wanted_co, vec);
bbd->wanted_speed = val->max_speed;
len = ptn[0].dist;
- ret = 1;
+ ret = true;
}
if (ptn) {
@@ -464,10 +464,10 @@ static int rule_separate(BoidRule *UNUSED(rule),
}
return ret;
}
-static int rule_flock(BoidRule *UNUSED(rule),
- BoidBrainData *bbd,
- BoidValues *UNUSED(val),
- ParticleData *pa)
+static bool rule_flock(BoidRule *UNUSED(rule),
+ BoidBrainData *bbd,
+ BoidValues *UNUSED(val),
+ ParticleData *pa)
{
KDTreeNearest_3d ptn[11];
float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
@@ -479,7 +479,7 @@ static int rule_flock(BoidRule *UNUSED(rule),
len_squared_v3v3_with_normal_bias,
pa->prev_state.ave);
int n;
- int ret = 0;
+ bool ret = false;
if (neighbors > 1) {
for (n = 1; n < neighbors; n++) {
@@ -497,20 +497,21 @@ static int rule_flock(BoidRule *UNUSED(rule),
add_v3_v3(bbd->wanted_co, loc);
bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
+ ret = true;
}
return ret;
}
-static int rule_follow_leader(BoidRule *rule,
- BoidBrainData *bbd,
- BoidValues *val,
- ParticleData *pa)
+static bool rule_follow_leader(BoidRule *rule,
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
float mul, len;
int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
- int i, ret = 0, p = pa - bbd->sim->psys->particles;
+ int i, p = pa - bbd->sim->psys->particles;
+ bool ret = false;
if (flbr->ob) {
float vec2[3], t;
@@ -530,7 +531,7 @@ static int rule_follow_leader(BoidRule *rule,
if (len < 2.0f * val->personal_space * pa->size) {
copy_v3_v3(bbd->wanted_co, loc);
bbd->wanted_speed = val->max_speed;
- return 1;
+ return true;
}
}
else {
@@ -548,7 +549,7 @@ static int rule_follow_leader(BoidRule *rule,
if (len < 2.0f * val->personal_space * pa->size) {
copy_v3_v3(bbd->wanted_co, vec2);
bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
- return 1;
+ return true;
}
}
}
@@ -570,7 +571,7 @@ static int rule_follow_leader(BoidRule *rule,
sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
+ ret = true;
}
else if (p % n) {
float vec2[3], t, t_min = 3.0f;
@@ -590,7 +591,7 @@ static int rule_follow_leader(BoidRule *rule,
if (len < 2.0f * val->personal_space * pa->size) {
copy_v3_v3(bbd->wanted_co, loc);
bbd->wanted_speed = val->max_speed;
- return 1;
+ return true;
}
}
else {
@@ -609,14 +610,14 @@ static int rule_follow_leader(BoidRule *rule,
t_min = t;
copy_v3_v3(bbd->wanted_co, loc);
bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
- ret = 1;
+ ret = true;
}
}
}
}
if (ret) {
- return 1;
+ return true;
}
/* not blocking so try to follow leader */
@@ -635,15 +636,15 @@ static int rule_follow_leader(BoidRule *rule,
sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
+ ret = true;
}
return ret;
}
-static int rule_average_speed(BoidRule *rule,
- BoidBrainData *bbd,
- BoidValues *val,
- ParticleData *pa)
+static bool rule_average_speed(BoidRule *rule,
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
BoidParticle *bpa = pa->boid;
BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed *)rule;
@@ -693,9 +694,9 @@ static int rule_average_speed(BoidRule *rule,
}
bbd->wanted_speed = asbr->speed * val->max_speed;
- return 1;
+ return true;
}
-static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
BoidRuleFight *fbr = (BoidRuleFight *)rule;
KDTreeNearest_3d *ptn = NULL;
@@ -708,7 +709,8 @@ static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti
float closest_dist = fbr->distance + 1.0f;
float f_strength = 0.0f, e_strength = 0.0f;
float health = 0.0f;
- int n, ret = 0;
+ int n;
+ bool ret = false;
/* calculate own group strength */
int neighbors = BLI_kdtree_3d_range_search(
@@ -799,16 +801,16 @@ static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti
}
}
- ret = 1;
+ ret = true;
}
return ret;
}
-typedef int (*boid_rule_cb)(BoidRule *rule,
- BoidBrainData *data,
- BoidValues *val,
- ParticleData *pa);
+typedef bool (*boid_rule_cb)(BoidRule *rule,
+ BoidBrainData *data,
+ BoidValues *val,
+ ParticleData *pa);
static boid_rule_cb boid_rules[] = {
rule_none,
@@ -957,24 +959,24 @@ static Object *boid_find_ground(BoidBrainData *bbd,
ground_nor[2] = 1.0f;
return NULL;
}
-static int boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule)
+static bool boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule)
{
BoidParticle *bpa = pa->boid;
if (rule == NULL) {
- return 0;
+ return false;
}
if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) &&
rule->flag & BOIDRULE_ON_LAND) {
- return 1;
+ return true;
}
if (bpa->data.mode == eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
void boids_precalc_rules(ParticleSettings *part, float cfra)
{
@@ -1025,27 +1027,27 @@ static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_n
return dot_v3v3(vec, goal_nor);
}
/* wanted_co is relative to boid location */
-static int apply_boid_rule(
+static bool apply_boid_rule(
BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
{
if (rule == NULL) {
- return 0;
+ return false;
}
- if (boid_rule_applies(pa, bbd->part->boids, rule) == 0) {
- return 0;
+ if (!boid_rule_applies(pa, bbd->part->boids, rule)) {
+ return false;
}
- if (boid_rules[rule->type](rule, bbd, val, pa) == 0) {
- return 0;
+ if (!boid_rules[rule->type](rule, bbd, val, pa)) {
+ return false;
}
if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co,
pa->prev_state.vel,
fuzziness * len_v3(pa->prev_state.vel)) == 0) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa)
{
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 8975be2b618..836ce542793 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -1182,10 +1182,10 @@ static bool collection_instance_find_recursive(Collection *collection,
/**
* Find potential cycles in collections.
*
- * \param new_ancestor the potential new owner of given \a collection, or the collection to check
- * if the later is NULL.
- * \param collection the collection we want to add to \a new_ancestor, may be NULL if we just want
- * to ensure \a new_ancestor does not already have cycles.
+ * \param new_ancestor: the potential new owner of given \a collection,
+ * or the collection to check if the later is NULL.
+ * \param collection: the collection we want to add to \a new_ancestor,
+ * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
* \return true if a cycle is found.
*/
bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
@@ -1254,7 +1254,7 @@ static bool collection_cycle_fix_recursive(Main *bmain,
/**
* Find and fix potential cycles in collections.
*
- * \param collection the collection to check for existing cycles.
+ * \param collection: The collection to check for existing cycles.
* \return true if cycles are found and fixed.
*/
bool BKE_collection_cycles_fix(Main *bmain, Collection *collection)
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 5a5fb7a36df..e2adaabca33 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -4342,10 +4342,10 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
* This means written typemap does not match written layers (as returned by \a r_write_layers).
* Trivial to fix is ever needed.
*/
-void CustomData_file_write_prepare(CustomData *data,
- CustomDataLayer **r_write_layers,
- CustomDataLayer *write_layers_buff,
- size_t write_layers_size)
+void CustomData_blend_write_prepare(CustomData *data,
+ CustomDataLayer **r_write_layers,
+ CustomDataLayer *write_layers_buff,
+ size_t write_layers_size)
{
CustomDataLayer *write_layers = write_layers_buff;
const size_t chunk_size = (write_layers_size > 0) ? write_layers_size : CD_TEMP_CHUNK_SIZE;
@@ -5193,13 +5193,16 @@ static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask
}
}
-void CustomData_blend_write(
- BlendWriter *writer, CustomData *data, int count, CustomDataMask cddata_mask, ID *id)
+/**
+ * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
+ */
+void CustomData_blend_write(BlendWriter *writer,
+ CustomData *data,
+ CustomDataLayer *layers,
+ int count,
+ CustomDataMask cddata_mask,
+ ID *id)
{
- CustomDataLayer *layers = NULL;
- CustomDataLayer layers_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_file_write_prepare(data, &layers, layers_buff, ARRAY_SIZE(layers_buff));
-
/* write external customdata (not for undo) */
if (data->external && !BLO_write_is_undo(writer)) {
CustomData_external_write(data, id, cddata_mask, count, 0);
@@ -5252,10 +5255,6 @@ void CustomData_blend_write(
if (data->external) {
BLO_write_struct(writer, CustomDataExternal, data->external);
}
-
- if (!ELEM(layers, NULL, layers_buff)) {
- MEM_freeN(layers);
- }
}
static void blend_read_mdisps(BlendDataReader *reader, int count, MDisps *mdisps, int external)
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index dff7dca4d76..50c9ce4fb75 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -306,12 +306,12 @@ static Mesh *dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
/***************************** General Utils ******************************/
/* Set canvas error string to display at the bake report */
-static int setError(DynamicPaintCanvasSettings *canvas, const char *string)
+static bool setError(DynamicPaintCanvasSettings *canvas, const char *string)
{
/* Add error to canvas ui info label */
BLI_strncpy(canvas->error, string, sizeof(canvas->error));
CLOG_STR_ERROR(&LOG, string);
- return 0;
+ return false;
}
/* Get number of surface points for cached types */
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index 4ab7d362e0e..6ef3817bc1c 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -155,10 +155,10 @@ static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
return NULL;
}
-/* Various helpers/wrappers around IDTypeInfo structure. */
+/* Various helpers/wrappers around #IDTypeInfo structure. */
/**
- * Convert an idcode into a name.
+ * Convert an \a idcode into a name.
*
* \param idcode: The code to convert.
* \return A static string representing the name of
@@ -172,7 +172,7 @@ const char *BKE_idtype_idcode_to_name(const short idcode)
}
/**
- * Convert an idcode into a name (plural).
+ * Convert an \a idcode into a name (plural).
*
* \param idcode: The code to convert.
* \return A static string representing the name of
@@ -186,7 +186,7 @@ const char *BKE_idtype_idcode_to_name_plural(const short idcode)
}
/**
- * Convert an idcode into its translations' context.
+ * Convert an \a idcode into its translations' context.
*
* \param idcode: The code to convert.
* \return A static string representing the i18n context of the code.
@@ -199,10 +199,10 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode)
}
/**
- * Convert an IDType name into an idcode (ie. ID_SCE)
+ * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
*
- * \param idtype_name: The IDType's 'user visible name' to convert.
- * \return The idcode for the name, or 0 if invalid.
+ * \param idtype_name: The ID-type's "user visible name" to convert.
+ * \return The \a idcode for the name, or 0 if invalid.
*/
short BKE_idtype_idcode_from_name(const char *idtype_name)
{
@@ -236,7 +236,7 @@ bool BKE_idtype_idcode_is_linkable(const short idcode)
}
/**
- * Convert an idcode into an idfilter (e.g. ID_OB -> FILTER_ID_OB).
+ * Convert an \a idcode into an \a idfilter (e.g. ID_OB -> FILTER_ID_OB).
*/
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
{
@@ -288,7 +288,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
}
/**
- * Convert an idfilter into an idcode (e.g. FILTER_ID_OB -> ID_OB).
+ * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
*/
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
{
@@ -339,7 +339,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
}
/**
- * Convert an idcode into an index (e.g. ID_OB -> INDEX_ID_OB).
+ * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
*/
int BKE_idtype_idcode_to_index(const short idcode)
{
@@ -401,7 +401,7 @@ int BKE_idtype_idcode_to_index(const short idcode)
}
/**
- * Get an idcode from an index (e.g. INDEX_ID_OB -> ID_OB).
+ * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
*/
short BKE_idtype_idcode_from_index(const int index)
{
@@ -473,7 +473,9 @@ short BKE_idtype_idcode_iter_step(int *index)
return (*index < ARRAY_SIZE(id_types)) ? BKE_idtype_idcode_from_index((*index)++) : 0;
}
-/** Wrapper around IDTypeInfo foreach_cache that also handles embedded IDs. */
+/**
+ * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
+ */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data)
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c
index 083d6c1d973..d4a1c1e2c46 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.c
@@ -39,7 +39,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_state.h"
#include "GPU_texture.h"
@@ -320,6 +320,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
*tex = IMB_create_gpu_texture(
ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied);
+ GPU_texture_wrap_mode(*tex, true, false);
+
if (GPU_mipmap_enabled()) {
GPU_texture_generate_mipmap(*tex);
if (ima) {
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 561db7d62c2..22ea5f2c854 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -56,10 +56,12 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
if (id->properties) {
IDP_FreePropertyContent_ex(id->properties, do_id_user);
MEM_freeN(id->properties);
+ id->properties = NULL;
}
if (id->override_library) {
BKE_lib_override_library_free(&id->override_library, do_id_user);
+ id->override_library = NULL;
}
BKE_animdata_free(id, do_id_user);
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 2908ef133f0..48ecbcae90c 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -409,9 +409,9 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
*
* This will include all local IDs, and all IDs from the same library as the \a id_root.
*
- * \param id_root The root of the hierarchy of dependencies to be tagged.
- * \param do_create_main_relashionships Whether main relations needs to be created or already exist
- * (in any case, they will be freed by this function).
+ * \param id_root: The root of the hierarchy of dependencies to be tagged.
+ * \param do_create_main_relashionships: Whether main relations needs to be created or already
+ * exist (in any case, they will be freed by this function).
*/
void BKE_lib_override_library_dependencies_tag(Main *bmain,
ID *id_root,
@@ -435,9 +435,9 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
* That is, all other liboverrides IDs (in)directly used by \a is_root one, sharing the same
* library for their reference IDs.
*
- * \param id_root The root of the hierarchy of liboverride dependencies to be tagged.
- * \param do_create_main_relashionships Whether main relations needs to be created or already exist
- * (in any case, they will be freed by this function).
+ * \param id_root: The root of the hierarchy of liboverride dependencies to be tagged.
+ * \param do_create_main_relashionships: Whether main relations needs to be created or already
+ * exist (in any case, they will be freed by this function).
*/
void BKE_lib_override_library_override_group_tag(Main *bmain,
ID *id_root,
@@ -640,10 +640,10 @@ static void lib_override_library_create_post_process(
* \note In the future that same function may be extended to support 'refresh' of overrides
* (rebuilding overrides from linked data, trying to preserve local overrides already defined).
*
- * \param id_root The root ID to create an override from.
- * \param id_reference some reference ID used to do some post-processing after overrides have been
- * created, may be NULL. Typically, the Empty object instantiating the linked
- * collection we override, currently.
+ * \param id_root: The root ID to create an override from.
+ * \param id_reference: Some reference ID used to do some post-processing after overrides have been
+ * created, may be NULL. Typically, the Empty object instantiating the linked
+ * collection we override, currently.
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_create(
@@ -668,7 +668,7 @@ bool BKE_lib_override_library_create(
* Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
* data, from an existing override hierarchy.
*
- * \param id_root The root liboverride ID to resync from.
+ * \param id_root: The root liboverride ID to resync from.
* \return true if override was successfully resynced.
*/
bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root)
@@ -790,7 +790,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
*
* \note All IDs tagged with `LIB_TAG_DOIT` will be deleted.
*
- * \param id_root The root liboverride ID to resync from.
+ * \param id_root: The root liboverride ID to resync from.
*/
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
{
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index a7568bcd6ea..0e6ef50f491 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -180,6 +180,18 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+ CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
+
+ CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ flayers = flayers_buff;
+ CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
+ CustomData_blend_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+
BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
BKE_id_blend_write(writer, &mesh->id);
@@ -191,12 +203,34 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect);
- CustomData_blend_write(writer, &mesh->vdata, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
- CustomData_blend_write(writer, &mesh->edata, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
+ CustomData_blend_write(
+ writer, &mesh->vdata, vlayers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
+ CustomData_blend_write(
+ writer, &mesh->edata, elayers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
/* fdata is really a dummy - written so slots align */
- CustomData_blend_write(writer, &mesh->fdata, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
- CustomData_blend_write(writer, &mesh->ldata, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
- CustomData_blend_write(writer, &mesh->pdata, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
+ CustomData_blend_write(
+ writer, &mesh->fdata, flayers, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
+ CustomData_blend_write(
+ writer, &mesh->ldata, llayers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
+ CustomData_blend_write(
+ writer, &mesh->pdata, players, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
+
+ /* Free temporary data */
+
+/* Free custom-data layers, when not assigned a buffer value. */
+#define CD_LAYERS_FREE(id) \
+ if (id && id != id##_buff) { \
+ MEM_freeN(id); \
+ } \
+ ((void)0)
+
+ CD_LAYERS_FREE(vlayers);
+ CD_LAYERS_FREE(elayers);
+ /* CD_LAYER_FREE(flayers); */ /* Never allocated. */
+ CD_LAYERS_FREE(llayers);
+ CD_LAYERS_FREE(players);
+
+#undef CD_LAYERS_FREE
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 8c5915d3768..6b433e5edaa 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1848,7 +1848,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
memset(pid, 0, sizeof(PTCacheID));
- pid->owner_id = &ob->id;
+ pid->owner_id = ob != NULL ? &ob->id : NULL;
pid->calldata = rbw;
pid->type = PTCACHE_TYPE_RIGIDBODY;
pid->cache = rbw->shared->pointcache;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 7eab716d805..0a31af032d3 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1554,18 +1554,18 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob, const bo
BKE_collection_object_add(bmain, scene->master_collection, ob);
}
BKE_collection_object_remove(bmain, rbw->group, ob, free_us);
+
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
+ /* Reset cache as the object order probably changed after freeing the object. */
+ PTCacheID pid;
+ BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
}
/* remove object's settings */
BKE_rigidbody_free_object(ob, rbw);
- /* flag cache as outdated */
- BKE_rigidbody_cache_reset(rbw);
- /* Reset cache as the object order probably changed after freeing the object. */
- PTCacheID pid;
- BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
-
/* Dependency graph update */
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 00218b1be51..34af226ef72 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -154,9 +154,11 @@ static void scene_init_data(ID *id)
scene->unit.system = USER_UNIT_METRIC;
scene->unit.scale_length = 1.0f;
- scene->unit.length_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
- scene->unit.mass_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
- scene->unit.time_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
+ scene->unit.length_unit = (uchar)BKE_unit_base_of_type_get(USER_UNIT_METRIC, B_UNIT_LENGTH);
+ scene->unit.mass_unit = (uchar)BKE_unit_base_of_type_get(USER_UNIT_METRIC, B_UNIT_MASS);
+ scene->unit.time_unit = (uchar)BKE_unit_base_of_type_get(USER_UNIT_METRIC, B_UNIT_TIME);
+ scene->unit.temperature_unit = (uchar)BKE_unit_base_of_type_get(USER_UNIT_METRIC,
+ B_UNIT_TEMPERATURE);
/* Anti-Aliasing threshold. */
scene->grease_pencil_settings.smaa_threshold = 1.0f;
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
index 3a7e4af490a..013abb716d4 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -483,7 +483,7 @@ static void *seq_prefetch_frames(void *job)
pfjob->running = false;
pfjob->scene_eval->ed->prefetch_job = NULL;
- return 0;
+ return NULL;
}
static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 5af24152972..bfa031f0d64 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -80,6 +80,8 @@
#define UN_SC_LB 0.45359237f
#define UN_SC_OZ 0.028349523125f
+#define UN_SC_FAH 0.555555555555f
+
/* clang-format on */
/* Define a single unit. */
@@ -101,7 +103,7 @@ typedef struct bUnitDef {
const char *identifier;
double scalar;
- /** Not used yet, needed for converting temperature. */
+ /** Needed for converting temperatures. */
double bias;
int flag;
} bUnitDef;
@@ -329,6 +331,22 @@ static struct bUnitDef buPowerDef[] = {
};
static struct bUnitCollection buPowerCollection = {buPowerDef, 3, 0, UNIT_COLLECTION_LENGTH(buPowerDef)};
+/* Temperature */
+static struct bUnitDef buMetricTempDef[] = {
+ {"kelvin", "kelvin", "K", NULL, "Kelvin", "KELVIN", 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
+ {"celsius", "celsius", "°C", "C", "Celsius", "CELCIUS", 1.0f, 273.15, B_UNIT_DEF_NONE},
+ NULL_UNIT,
+};
+static struct bUnitCollection buMetricTempCollection = {buMetricTempDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricTempDef)};
+
+static struct bUnitDef buImperialTempDef[] = {
+ {"kelvin", "kelvin", "K", NULL, "Kelvin", "KELVIN", 1.0f, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
+ {"fahrenheit", "fahrenheit", "°F", "F", "Fahrenheit", "FAHRENHEIT", UN_SC_FAH, 459.67, B_UNIT_DEF_NONE},
+ NULL_UNIT,
+};
+static struct bUnitCollection buImperialTempCollection = {
+ buImperialTempDef, 1, 0, UNIT_COLLECTION_LENGTH(buImperialTempDef)};
+
/* clang-format on */
#define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
@@ -344,6 +362,7 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
NULL,
NULL,
NULL,
+ NULL,
NULL},
/* Metric. */
{NULL,
@@ -356,7 +375,8 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
&buMetricVelCollection,
&buMetricAclCollection,
&buCameraLenCollection,
- &buPowerCollection},
+ &buPowerCollection,
+ &buMetricTempCollection},
/* Imperial. */
{NULL,
&buImperialLenCollection,
@@ -368,7 +388,8 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
&buImperialVelCollection,
&buImperialAclCollection,
&buCameraLenCollection,
- &buPowerCollection},
+ &buPowerCollection,
+ &buImperialTempCollection},
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
};
@@ -449,7 +470,7 @@ static size_t unit_as_string(char *str,
}
}
- double value_conv = value / unit->scalar;
+ double value_conv = (value / unit->scalar) - unit->bias;
/* Adjust precision to expected number of significant digits.
* Note that here, we shall not have to worry about very big/small numbers, units are expected
@@ -512,6 +533,7 @@ typedef struct {
int length;
int mass;
int time;
+ int temperature;
} PreferredUnits;
static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings)
@@ -522,6 +544,7 @@ static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *sett
units.length = settings->length_unit;
units.mass = settings->mass_unit;
units.time = settings->time_unit;
+ units.temperature = settings->temperature_unit;
return units;
}
@@ -597,6 +620,11 @@ static const bUnitDef *get_preferred_display_unit_if_used(int type, PreferredUni
return usys->units + 3;
}
break;
+ case B_UNIT_TEMPERATURE:
+ if (units.temperature == USER_UNIT_ADAPTIVE) {
+ return NULL;
+ }
+ return usys->units + MIN2(units.temperature, max_offset);
default:
break;
}
@@ -634,7 +662,7 @@ static size_t unit_as_string_main(char *str,
return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0');
}
-size_t bUnit_AsString(
+size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
{
PreferredUnits units;
@@ -643,16 +671,17 @@ size_t bUnit_AsString(
units.length = USER_UNIT_ADAPTIVE;
units.mass = USER_UNIT_ADAPTIVE;
units.time = USER_UNIT_ADAPTIVE;
+ units.temperature = USER_UNIT_ADAPTIVE;
return unit_as_string_main(str, len_max, value, prec, type, split, pad, units);
}
-size_t bUnit_AsString2(char *str,
- int len_max,
- double value,
- int prec,
- int type,
- const UnitSettings *settings,
- bool pad)
+size_t BKE_unit_value_as_string(char *str,
+ int len_max,
+ double value,
+ int prec,
+ int type,
+ const UnitSettings *settings,
+ bool pad)
{
bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0;
PreferredUnits units = preferred_units_from_UnitSettings(settings);
@@ -844,6 +873,35 @@ static bool unit_distribute_negatives(char *str, const int len_max)
return changed;
}
+/**
+ * Helper for #unit_scale_str for the process of correctly applying the order of operations
+ * for the unit's bias term.
+ */
+static int find_previous_non_value_char(const char *str, const int start_ofs)
+{
+ for (int i = start_ofs; i > 0; i--) {
+ if (ch_is_op(str[i - 1]) || strchr("( )", str[i - 1])) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Helper for #unit_scale_str for the process of correctly applying the order of operations
+ * for the unit's bias term.
+ */
+static int find_end_of_value_chars(const char *str, const int len_max, const int start_ofs)
+{
+ int i;
+ for (i = start_ofs; i < len_max; i++) {
+ if (!strchr("0123456789eE.", str[i])) {
+ return i;
+ }
+ }
+ return i;
+}
+
static int unit_scale_str(char *str,
int len_max,
char *str_tmp,
@@ -867,6 +925,34 @@ static int unit_scale_str(char *str,
int len = strlen(str);
+ /* Deal with unit bias for temperature units. Order of operations is important, so we
+ * have to add parentheses, add the bias, then multiply by the scalar like usual.
+ *
+ * Note: If these changes don't fit in the buffer properly unit evaluation has failed,
+ * just try not to destroy anything while failing. */
+ if (unit->bias != 0.0) {
+ /* Add the open parenthesis. */
+ int prev_op_ofs = find_previous_non_value_char(str, found_ofs);
+ if (len + 1 < len_max) {
+ memmove(str + prev_op_ofs + 1, str + prev_op_ofs, len - prev_op_ofs + 1);
+ str[prev_op_ofs] = '(';
+ len++;
+ found_ofs++;
+ str_found++;
+ } /* If this doesn't fit, we have failed. */
+
+ /* Add the addition sign, the bias, and the close parenthesis after the value. */
+ int value_end_ofs = find_end_of_value_chars(str, len_max, prev_op_ofs + 2);
+ int len_bias_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "+%.9g)", unit->bias);
+ if (value_end_ofs + len_bias_num < len_max) {
+ memmove(str + value_end_ofs + len_bias_num, str + value_end_ofs, len - value_end_ofs + 1);
+ memcpy(str + value_end_ofs, str_tmp, len_bias_num);
+ len += len_bias_num;
+ found_ofs += len_bias_num;
+ str_found += len_bias_num;
+ } /* If this doesn't fit, we have failed. */
+ }
+
int len_name = strlen(replace_str);
int len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator. */
@@ -973,7 +1059,7 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys,
return unit;
}
-bool bUnit_ContainsUnit(const char *str, int type)
+bool BKE_unit_string_contains_unit(const char *str, int type)
{
for (int system = 0; system < UNIT_SYSTEM_TOT; system++) {
const bUnitCollection *usys = unit_get_system(system, type);
@@ -990,15 +1076,15 @@ bool bUnit_ContainsUnit(const char *str, int type)
return false;
}
-double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int type)
+double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value)
{
PreferredUnits units = preferred_units_from_UnitSettings(settings);
const bUnitDef *unit = get_preferred_display_unit_if_used(type, units);
- if (unit) {
- return unit->scalar;
- }
- return bUnit_BaseScalar(units.system, type);
+ const double scalar = (unit == NULL) ? BKE_unit_base_scalar(units.system, type) : unit->scalar;
+ const double bias = (unit == NULL) ? 0.0 : unit->bias; /* Base unit shouldn't have a bias. */
+
+ return value * scalar + bias;
}
/**
@@ -1013,11 +1099,11 @@ double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int t
* Values will be split by an add sign.
* 5'2" -> 5*0.3048 + 2*0.0254
*
- * \param str_prev is optional, when valid it is used to get a base unit when none is set.
+ * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
*
* \return True of a change was made.
*/
-bool bUnit_ReplaceString(
+bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
@@ -1047,7 +1133,7 @@ bool bUnit_ReplaceString(
}
else {
/* BLI_snprintf would not fit into str_tmp, cant do much in this case.
- * Check for this because otherwise bUnit_ReplaceString could call its self forever. */
+ * Check for this because otherwise BKE_unit_replace_string could call its self forever. */
return changed;
}
@@ -1108,7 +1194,7 @@ bool bUnit_ReplaceString(
}
/* 45µm --> 45um */
-void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type)
+void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
@@ -1148,7 +1234,7 @@ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int syste
strncpy(str, orig_str, len_max);
}
-double bUnit_ClosestScalar(double value, int system, int type)
+double BKE_unit_closest_scalar(double value, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
@@ -1164,7 +1250,7 @@ double bUnit_ClosestScalar(double value, int system, int type)
return unit->scalar;
}
-double bUnit_BaseScalar(int system, int type)
+double BKE_unit_base_scalar(int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
if (usys) {
@@ -1174,12 +1260,12 @@ double bUnit_BaseScalar(int system, int type)
return 1.0;
}
-bool bUnit_IsValid(int system, int type)
+bool BKE_unit_is_valid(int system, int type)
{
return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
}
-void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len)
+void BKE_unit_system_get(int system, int type, void const **r_usys_pt, int *r_len)
{
const bUnitCollection *usys = unit_get_system(system, type);
*r_usys_pt = usys;
@@ -1192,25 +1278,25 @@ void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len)
*r_len = usys->length;
}
-int bUnit_GetBaseUnit(const void *usys_pt)
+int BKE_unit_base_get(const void *usys_pt)
{
return ((bUnitCollection *)usys_pt)->base_unit;
}
-int bUnit_GetBaseUnitOfType(int system, int type)
+int BKE_unit_base_of_type_get(int system, int type)
{
return unit_get_system(system, type)->base_unit;
}
-const char *bUnit_GetName(const void *usys_pt, int index)
+const char *BKE_unit_name_get(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name;
}
-const char *bUnit_GetNameDisplay(const void *usys_pt, int index)
+const char *BKE_unit_display_name_get(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name_display;
}
-const char *bUnit_GetIdentifier(const void *usys_pt, int index)
+const char *BKE_unit_identifier_get(const void *usys_pt, int index)
{
const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
if (unit->identifier == NULL) {
@@ -1219,12 +1305,12 @@ const char *bUnit_GetIdentifier(const void *usys_pt, int index)
return unit->identifier;
}
-double bUnit_GetScaler(const void *usys_pt, int index)
+double BKE_unit_scalar_get(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].scalar;
}
-bool bUnit_IsSuppressed(const void *usys_pt, int index)
+bool BKE_unit_is_suppressed(const void *usys_pt, int index)
{
return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
}
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index dddf4f64ff5..8a7dcb7ffaa 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -353,6 +353,10 @@ class Array {
{
return allocator_;
}
+ const Allocator &allocator() const
+ {
+ return allocator_;
+ }
/**
* Get the value of the InlineBufferCapacity template argument. This is the number of elements
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index be18848fbf4..8e3e3be99e2 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -404,6 +404,26 @@ inline bool operator!=(StringRef a, StringRef b)
return !(a == b);
}
+inline bool operator<(StringRef a, StringRef b)
+{
+ return std::string_view(a) < std::string_view(b);
+}
+
+inline bool operator>(StringRef a, StringRef b)
+{
+ return std::string_view(a) > std::string_view(b);
+}
+
+inline bool operator<=(StringRef a, StringRef b)
+{
+ return std::string_view(a) <= std::string_view(b);
+}
+
+inline bool operator>=(StringRef a, StringRef b)
+{
+ return std::string_view(a) >= std::string_view(b);
+}
+
/**
* Return true when the string starts with the given prefix.
*/
diff --git a/source/blender/blenlib/BLI_string_search.h b/source/blender/blenlib/BLI_string_search.h
new file mode 100644
index 00000000000..8057e5b75cb
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_search.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct StringSearch StringSearch;
+
+StringSearch *BLI_string_search_new(void);
+void BLI_string_search_add(StringSearch *search, const char *str, void *user_data);
+int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data);
+void BLI_string_search_free(StringSearch *search);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+# include "BLI_linear_allocator.hh"
+# include "BLI_span.hh"
+# include "BLI_string_ref.hh"
+# include "BLI_vector.hh"
+
+namespace blender::string_search {
+
+int damerau_levenshtein_distance(StringRef a, StringRef b);
+int get_fuzzy_match_errors(StringRef query, StringRef full);
+void extract_normalized_words(StringRef str,
+ LinearAllocator<> &allocator,
+ Vector<StringRef, 64> &r_words);
+
+} // namespace blender::string_search
+
+#endif
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 9d7c61f9e3b..c9773dc599d 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -143,7 +143,7 @@ class VectorSet {
* no keys are removed. The first set->size() elements in this array are initialized. The
* capacity of the array is usable_slots_.
*/
- Key *keys_;
+ Key *keys_ = nullptr;
/** Iterate over a slot index sequence for a given hash. */
#define VECTOR_SET_SLOT_PROBING_BEGIN(HASH, R_SLOT) \
@@ -157,22 +157,31 @@ class VectorSet {
* necessary to avoid a high cost when no elements are added at all. An optimized grow operation
* is performed on the first insertion.
*/
- VectorSet()
+ VectorSet(Allocator allocator = {}) noexcept
: removed_slots_(0),
occupied_and_removed_slots_(0),
usable_slots_(0),
slot_mask_(0),
- slots_(1),
+ slots_(1, allocator),
keys_(nullptr)
{
}
+ VectorSet(NoExceptConstructor, Allocator allocator = {}) : VectorSet(allocator)
+ {
+ }
+
+ VectorSet(Span<Key> keys, Allocator allocator = {}) : VectorSet(NoExceptConstructor(), allocator)
+ {
+ this->add_multiple(keys);
+ }
+
/**
* Construct a vector set that contains the given keys. Duplicates will be removed automatically.
*/
- VectorSet(const std::initializer_list<Key> &keys) : VectorSet()
+ VectorSet(const std::initializer_list<Key> &keys, Allocator allocator = {})
+ : VectorSet(Span(keys), allocator)
{
- this->add_multiple(keys);
}
~VectorSet()
@@ -183,15 +192,23 @@ class VectorSet {
}
}
- VectorSet(const VectorSet &other)
- : removed_slots_(other.removed_slots_),
- occupied_and_removed_slots_(other.occupied_and_removed_slots_),
- usable_slots_(other.usable_slots_),
- slot_mask_(other.slot_mask_),
- slots_(other.slots_)
+ VectorSet(const VectorSet &other) : slots_(other.slots_)
{
- keys_ = this->allocate_keys_array(usable_slots_);
- uninitialized_copy_n(other.keys_, other.size(), keys_);
+ keys_ = this->allocate_keys_array(other.usable_slots_);
+ try {
+ uninitialized_copy_n(other.keys_, other.size(), keys_);
+ }
+ catch (...) {
+ this->deallocate_keys_array(keys_);
+ throw;
+ }
+
+ removed_slots_ = other.removed_slots_;
+ occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
+ usable_slots_ = other.usable_slots_;
+ slot_mask_ = other.slot_mask_;
+ hash_ = other.hash_;
+ is_equal_ = other.is_equal_;
}
VectorSet(VectorSet &&other) noexcept
@@ -212,26 +229,12 @@ class VectorSet {
VectorSet &operator=(const VectorSet &other)
{
- if (this == &other) {
- return *this;
- }
-
- this->~VectorSet();
- new (this) VectorSet(other);
-
- return *this;
+ return copy_assign_container(*this, other);
}
VectorSet &operator=(VectorSet &&other)
{
- if (this == &other) {
- return *this;
- }
-
- this->~VectorSet();
- new (this) VectorSet(std::move(other));
-
- return *this;
+ return move_assign_container(*this, std::move(other));
}
/**
@@ -490,32 +493,48 @@ class VectorSet {
/* Optimize the case when the set was empty beforehand. We can avoid some copies here. */
if (this->size() == 0) {
- slots_.~Array();
- new (&slots_) SlotArray(total_slots);
+ try {
+ slots_.reinitialize(total_slots);
+ keys_ = this->allocate_keys_array(usable_slots);
+ }
+ catch (...) {
+ this->noexcept_reset();
+ throw;
+ }
removed_slots_ = 0;
occupied_and_removed_slots_ = 0;
usable_slots_ = usable_slots;
slot_mask_ = new_slot_mask;
- keys_ = this->allocate_keys_array(usable_slots);
return;
}
SlotArray new_slots(total_slots);
- for (Slot &slot : slots_) {
- if (slot.is_occupied()) {
- this->add_after_grow_and_destruct_old(slot, new_slots, new_slot_mask);
+ try {
+ for (Slot &slot : slots_) {
+ if (slot.is_occupied()) {
+ this->add_after_grow(slot, new_slots, new_slot_mask);
+ slot.remove();
+ }
}
+ slots_ = std::move(new_slots);
+ }
+ catch (...) {
+ this->noexcept_reset();
+ throw;
}
Key *new_keys = this->allocate_keys_array(usable_slots);
- uninitialized_relocate_n(keys_, this->size(), new_keys);
+ try {
+ uninitialized_relocate_n(keys_, this->size(), new_keys);
+ }
+ catch (...) {
+ this->deallocate_keys_array(new_keys);
+ this->noexcept_reset();
+ throw;
+ }
this->deallocate_keys_array(keys_);
- /* All occupied slots have been destructed already and empty/removed slots are assumed to be
- * trivially destructible. */
- slots_.clear_without_destruct();
- slots_ = std::move(new_slots);
keys_ = new_keys;
occupied_and_removed_slots_ -= removed_slots_;
usable_slots_ = usable_slots;
@@ -523,9 +542,7 @@ class VectorSet {
slot_mask_ = new_slot_mask;
}
- void add_after_grow_and_destruct_old(Slot &old_slot,
- SlotArray &new_slots,
- const uint64_t new_slot_mask)
+ void add_after_grow(Slot &old_slot, SlotArray &new_slots, const uint64_t new_slot_mask)
{
const Key &key = keys_[old_slot.index()];
const uint64_t hash = old_slot.get_hash(key, Hash());
@@ -533,13 +550,20 @@ class VectorSet {
SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
Slot &slot = new_slots[slot_index];
if (slot.is_empty()) {
- slot.relocate_occupied_here(old_slot, hash);
+ slot.occupy(old_slot.index(), hash);
return;
}
}
SLOT_PROBING_END();
}
+ void noexcept_reset() noexcept
+ {
+ Allocator allocator = slots_.allocator();
+ this->~VectorSet();
+ new (this) VectorSet(NoExceptConstructor(), allocator);
+ }
+
template<typename ForwardKey>
bool contains__impl(const ForwardKey &key, const uint64_t hash) const
{
@@ -580,8 +604,8 @@ class VectorSet {
if (slot.is_empty()) {
int64_t index = this->size();
new (keys_ + index) Key(std::forward<ForwardKey>(key));
- occupied_and_removed_slots_++;
slot.occupy(index, hash);
+ occupied_and_removed_slots_++;
return true;
}
if (slot.contains(key, is_equal_, hash, keys_)) {
diff --git a/source/blender/blenlib/BLI_vector_set_slots.hh b/source/blender/blenlib/BLI_vector_set_slots.hh
index 0e75c4690a4..b79341ed744 100644
--- a/source/blender/blenlib/BLI_vector_set_slots.hh
+++ b/source/blender/blenlib/BLI_vector_set_slots.hh
@@ -97,18 +97,6 @@ template<typename Key> class SimpleVectorSetSlot {
}
/**
- * Move the other slot into this slot and destruct it. We do destruction here, because this way
- * we can avoid a comparison with the state, since we know the slot is occupied. For this
- * specific slot implementation, this does not make a difference.
- */
- void relocate_occupied_here(SimpleVectorSetSlot &other, uint64_t UNUSED(hash))
- {
- BLI_assert(!this->is_occupied());
- BLI_assert(other.is_occupied());
- state_ = other.state_;
- }
-
- /**
* Change the state of this slot from empty/removed to occupied. The hash can be used by other
* slot implementations.
*/
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index a0569ad3dd4..e01459ac80e 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -124,6 +124,7 @@ set(SRC
intern/storage.c
intern/string.c
intern/string_cursor_utf8.c
+ intern/string_search.cc
intern/string_utf8.c
intern/string_utils.c
intern/system.c
@@ -267,6 +268,7 @@ set(SRC
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
+ BLI_string_search.h
BLI_string_ref.hh
BLI_string_utf8.h
BLI_string_utils.h
@@ -411,6 +413,7 @@ if(WITH_GTESTS)
tests/BLI_span_test.cc
tests/BLI_stack_cxx_test.cc
tests/BLI_stack_test.cc
+ tests/BLI_string_search_test.cc
tests/BLI_string_ref_test.cc
tests/BLI_string_test.cc
tests/BLI_string_utf8_test.cc
diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c
index d1e2bd58909..eb7e5ca6658 100644
--- a/source/blender/blenlib/intern/polyfill_2d.c
+++ b/source/blender/blenlib/intern/polyfill_2d.c
@@ -907,6 +907,19 @@ void BLI_polyfill_calc(const float (*coords)[2],
const int coords_sign,
uint (*r_tris)[3])
{
+ /* Fallback to heap memory for large allocations.
+ * Avoid running out of stack memory on systems with 512kb stack (macOS).
+ * This happens at around 13,000 points, use a much lower value to be safe. */
+ if (UNLIKELY(coords_tot > 8192)) {
+ /* The buffer size only accounts for the index allocation,
+ * worst case we do two allocations when concave, while we should try to be efficient,
+ * any caller that relies on this frequently should use #BLI_polyfill_calc_arena directly. */
+ MemArena *arena = BLI_memarena_new(sizeof(PolyIndex) * coords_tot, __func__);
+ BLI_polyfill_calc_arena(coords, coords_tot, coords_sign, r_tris, arena);
+ BLI_memarena_free(arena);
+ return;
+ }
+
PolyFill pf;
PolyIndex *indices = BLI_array_alloca(indices, coords_tot);
diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc
new file mode 100644
index 00000000000..17da3b9f493
--- /dev/null
+++ b/source/blender/blenlib/intern/string_search.cc
@@ -0,0 +1,475 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_array.hh"
+#include "BLI_linear_allocator.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_span.hh"
+#include "BLI_string.h"
+#include "BLI_string_ref.hh"
+#include "BLI_string_search.h"
+#include "BLI_string_utf8.h"
+#include "BLI_timeit.hh"
+
+namespace blender::string_search {
+
+static int64_t count_utf8_code_points(StringRef str)
+{
+ return static_cast<int64_t>(BLI_strnlen_utf8(str.data(), static_cast<size_t>(str.size())));
+}
+
+/**
+ * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
+ * operations that need to be executed. Valid operations are deletion, insertion, substitution and
+ * transposition.
+ *
+ * This function is utf8 aware in the sense that it works at the level of individual code points
+ * (1-4 bytes long) instead of on individual bytes.
+ */
+int damerau_levenshtein_distance(StringRef a, StringRef b)
+{
+ constexpr int deletion_cost = 1;
+ constexpr int insertion_cost = 1;
+ constexpr int substitution_cost = 1;
+ constexpr int transposition_cost = 1;
+
+ const int size_a = count_utf8_code_points(a);
+ const int size_b = count_utf8_code_points(b);
+
+ /* Instead of keeping the entire table in memory, only keep three rows. The algorithm only
+ * accesses these rows and nothing older.
+ * All three rows are usually allocated on the stack. At most a single heap allocation is done,
+ * if the reserved stack space is too small. */
+ const int row_length = size_b + 1;
+ Array<int, 64> rows(row_length * 3);
+
+ /* Store rows as spans so that it is cheap to swap them. */
+ MutableSpan v0{rows.data() + row_length * 0, row_length};
+ MutableSpan v1{rows.data() + row_length * 1, row_length};
+ MutableSpan v2{rows.data() + row_length * 2, row_length};
+
+ /* Only v1 needs to be initialized. */
+ for (const int i : IndexRange(row_length)) {
+ v1[i] = i * insertion_cost;
+ }
+
+ uint32_t prev_unicode_a;
+ size_t offset_a = 0;
+ for (const int i : IndexRange(size_a)) {
+ v2[0] = (i + 1) * deletion_cost;
+
+ const uint32_t unicode_a = BLI_str_utf8_as_unicode_and_size(a.data() + offset_a, &offset_a);
+
+ uint32_t prev_unicode_b;
+ size_t offset_b = 0;
+ for (const int j : IndexRange(size_b)) {
+ const uint32_t unicode_b = BLI_str_utf8_as_unicode_and_size(b.data() + offset_b, &offset_b);
+
+ /* Check how costly the different operations would be and pick the cheapest - the one with
+ * minimal cost. */
+ int new_cost = std::min({v1[j + 1] + deletion_cost,
+ v2[j] + insertion_cost,
+ v1[j] + (unicode_a != unicode_b) * substitution_cost});
+ if (i > 0 && j > 0) {
+ if (unicode_a == prev_unicode_b && prev_unicode_a == unicode_b) {
+ new_cost = std::min(new_cost, v0[j - 1] + transposition_cost);
+ }
+ }
+
+ v2[j + 1] = new_cost;
+ prev_unicode_b = unicode_b;
+ }
+
+ /* Swap the three rows, so that the next row can be computed. */
+ std::tie(v0, v1, v2) = std::tuple<MutableSpan<int>, MutableSpan<int>, MutableSpan<int>>(
+ v1, v2, v0);
+ prev_unicode_a = unicode_a;
+ }
+
+ return v1.last();
+}
+
+/**
+ * Returns -1 when this is no reasonably good match.
+ * Otherwise returns the number of errors in the match.
+ */
+int get_fuzzy_match_errors(StringRef query, StringRef full)
+{
+ /* If it is a perfect partial match, return immediatly. */
+ if (full.find(query) != StringRef::not_found) {
+ return 0;
+ }
+
+ const int query_size = count_utf8_code_points(query);
+ const int full_size = count_utf8_code_points(full);
+
+ /* If there is only a single character which is not in the full string, this is not a match. */
+ if (query_size == 1) {
+ return -1;
+ }
+ BLI_assert(query.size() >= 2);
+
+ /* Allow more errors when the size grows larger. */
+ const int max_errors = query_size <= 1 ? 0 : query_size / 8 + 1;
+
+ /* If the query is too large, this cannot be a match. */
+ if (query_size - full_size > max_errors) {
+ return -1;
+ }
+
+ const uint32_t query_first_unicode = BLI_str_utf8_as_unicode(query.data());
+ const uint32_t query_second_unicode = BLI_str_utf8_as_unicode(query.data() +
+ BLI_str_utf8_size(query.data()));
+
+ const char *full_begin = full.begin();
+ const char *full_end = full.end();
+
+ const char *window_begin = full_begin;
+ const char *window_end = window_begin;
+ const int window_size = std::min(query_size + max_errors, full_size);
+ const int extra_chars = window_size - query_size;
+ const int max_acceptable_distance = max_errors + extra_chars;
+
+ for (int i = 0; i < window_size; i++) {
+ window_end += BLI_str_utf8_size(window_end);
+ }
+
+ while (true) {
+ StringRef window{window_begin, window_end};
+ const uint32_t window_begin_unicode = BLI_str_utf8_as_unicode(window_begin);
+ int distance = 0;
+ /* Expect that the first or second character of the query is correct. This helps to avoid
+ * computing the more expensive distance function. */
+ if (ELEM(window_begin_unicode, query_first_unicode, query_second_unicode)) {
+ distance = damerau_levenshtein_distance(query, window);
+ if (distance <= max_acceptable_distance) {
+ return distance;
+ }
+ }
+ if (window_end == full_end) {
+ return -1;
+ }
+
+ /* When the distance is way too large, we can skip a couple of code points, because the
+ * distance can't possibly become as short as required. */
+ const int window_offset = std::max(1, distance / 2);
+ for (int i = 0; i < window_offset && window_end < full_end; i++) {
+ window_begin += BLI_str_utf8_size(window_begin);
+ window_end += BLI_str_utf8_size(window_end);
+ }
+ }
+}
+
+/**
+ * Takes a query and tries to match it with the first characters of some words. For example, "msfv"
+ * matches "Mark Sharp from Vertices". Multiple letters of the beginning of a word can be matched
+ * as well. For example, "seboulo" matches "select boundary loop". The order of words is important.
+ * So "bose" does not match "select boundary". However, individual words can be skipped. For
+ * example, "rocc" matches "rotate edge ccw".
+ *
+ * Returns true when the match was successfull. If it was successfull, the used words are tagged in
+ * r_word_is_matched.
+ */
+static bool match_word_initials(StringRef query,
+ Span<StringRef> words,
+ Span<bool> word_is_usable,
+ MutableSpan<bool> r_word_is_matched,
+ int start = 0)
+{
+ if (start >= words.size()) {
+ return false;
+ }
+
+ r_word_is_matched.fill(false);
+
+ size_t query_index = 0;
+ int word_index = start;
+ size_t char_index = 0;
+
+ int first_found_word_index = -1;
+
+ while (query_index < query.size()) {
+ const uint query_unicode = BLI_str_utf8_as_unicode_and_size(query.data() + query_index,
+ &query_index);
+ while (true) {
+ /* We are at the end of words, no complete match has been found yet. */
+ if (word_index >= words.size()) {
+ if (first_found_word_index >= 0) {
+ /* Try starting to match at another word. In some cases one can still find matches this
+ * way. */
+ return match_word_initials(
+ query, words, word_is_usable, r_word_is_matched, first_found_word_index + 1);
+ }
+ return false;
+ }
+
+ /* Skip words that the caller does not want us to use. */
+ if (!word_is_usable[word_index]) {
+ word_index++;
+ BLI_assert(char_index == 0);
+ continue;
+ }
+
+ StringRef word = words[word_index];
+ /* Try to match the current character with the current word. */
+ if (static_cast<int>(char_index) < word.size()) {
+ const uint32_t char_unicode = BLI_str_utf8_as_unicode_and_size(word.data() + char_index,
+ &char_index);
+ if (query_unicode == char_unicode) {
+ r_word_is_matched[word_index] = true;
+ if (first_found_word_index == -1) {
+ first_found_word_index = word_index;
+ }
+ break;
+ }
+ }
+
+ /* Could not find a match in the current word, go to the beginning of the next word. */
+ word_index += 1;
+ char_index = 0;
+ }
+ }
+ return true;
+}
+
+static int get_shortest_word_index_that_startswith(StringRef query,
+ Span<StringRef> words,
+ Span<bool> word_is_usable)
+{
+ int best_word_size = INT32_MAX;
+ int bset_word_index = -1;
+ for (const int i : words.index_range()) {
+ if (!word_is_usable[i]) {
+ continue;
+ }
+ StringRef word = words[i];
+ if (word.startswith(query)) {
+ if (word.size() < best_word_size) {
+ bset_word_index = i;
+ }
+ }
+ }
+ return bset_word_index;
+}
+
+static int get_word_index_that_fuzzy_matches(StringRef query,
+ Span<StringRef> words,
+ Span<bool> word_is_usable,
+ int *r_error_count)
+{
+ for (const int i : words.index_range()) {
+ if (!word_is_usable[i]) {
+ continue;
+ }
+ StringRef word = words[i];
+ const int error_count = get_fuzzy_match_errors(query, word);
+ if (error_count >= 0) {
+ *r_error_count = error_count;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Checks how well the query matches a result. If it does not match, -1 is returned. A positive
+ * return value indicates how good the match is. The higher the value, the better the match.
+ */
+static int score_query_against_words(Span<StringRef> query_words, Span<StringRef> result_words)
+{
+ /* Remember which words have been matched, so that they are not matched again. */
+ Array<bool, 64> word_is_usable(result_words.size(), true);
+
+ /* Start with some high score, because otherwise the final score might become negative. */
+ int total_match_score = 1000;
+
+ for (StringRef query_word : query_words) {
+ {
+ /* Check if any result word begins with the query word. */
+ const int word_index = get_shortest_word_index_that_startswith(
+ query_word, result_words, word_is_usable);
+ if (word_index >= 0) {
+ total_match_score += 10;
+ word_is_usable[word_index] = false;
+ continue;
+ }
+ }
+ {
+ /* Try to match against word initials. */
+ Array<bool, 64> matched_words(result_words.size());
+ const bool success = match_word_initials(
+ query_word, result_words, word_is_usable, matched_words);
+ if (success) {
+ total_match_score += 3;
+ for (const int i : result_words.index_range()) {
+ if (matched_words[i]) {
+ word_is_usable[i] = false;
+ }
+ }
+ continue;
+ }
+ }
+ {
+ /* Fuzzy match against words. */
+ int error_count = 0;
+ const int word_index = get_word_index_that_fuzzy_matches(
+ query_word, result_words, word_is_usable, &error_count);
+ if (word_index >= 0) {
+ total_match_score += 3 - error_count;
+ word_is_usable[word_index] = false;
+ continue;
+ }
+ }
+
+ /* Couldn't match query word with anything. */
+ return -1;
+ }
+
+ return total_match_score;
+}
+
+/**
+ * Splits a string into words and normalizes them (currently that just means converting to lower
+ * case). The returned strings are allocated in the given allocator.
+ */
+void extract_normalized_words(StringRef str,
+ LinearAllocator<> &allocator,
+ Vector<StringRef, 64> &r_words)
+{
+ const uint32_t unicode_space = BLI_str_utf8_as_unicode(" ");
+ const uint32_t unicode_right_triangle = BLI_str_utf8_as_unicode("â–¶");
+
+ auto is_separator = [&](uint32_t unicode) {
+ return ELEM(unicode, unicode_space, unicode_right_triangle);
+ };
+
+ /* Make a copy of the string so that we can edit it. */
+ StringRef str_copy = allocator.copy_string(str);
+ char *mutable_copy = const_cast<char *>(str_copy.data());
+ const size_t str_size_in_bytes = static_cast<size_t>(str.size());
+ BLI_str_tolower_ascii(mutable_copy, str_size_in_bytes);
+
+ /* Iterate over all unicode code points to split individual words. */
+ bool is_in_word = false;
+ size_t word_start = 0;
+ size_t offset = 0;
+ while (offset < str_size_in_bytes) {
+ size_t size = 0;
+ uint32_t unicode = BLI_str_utf8_as_unicode_and_size(str.data() + offset, &size);
+ if (is_separator(unicode)) {
+ if (is_in_word) {
+ r_words.append(
+ str_copy.substr(static_cast<int>(word_start), static_cast<int>(offset - word_start)));
+ is_in_word = false;
+ }
+ }
+ else {
+ if (!is_in_word) {
+ word_start = offset;
+ is_in_word = true;
+ }
+ }
+ offset += size;
+ }
+ /* If the last word is not followed by a separator, it has to be handld separately. */
+ if (is_in_word) {
+ r_words.append(str_copy.drop_prefix(static_cast<int>(word_start)));
+ }
+}
+
+} // namespace blender::string_search
+
+struct SearchItem {
+ blender::Span<blender::StringRef> normalized_words;
+ void *user_data;
+};
+
+struct StringSearch {
+ blender::LinearAllocator<> allocator;
+ blender::Vector<SearchItem> items;
+};
+
+StringSearch *BLI_string_search_new()
+{
+ return new StringSearch();
+}
+
+/**
+ * Add a new possible result to the search.
+ * The caller keeps ownership of all parameters.
+ */
+void BLI_string_search_add(StringSearch *search, const char *str, void *user_data)
+{
+ using namespace blender;
+ Vector<StringRef, 64> words;
+ string_search::extract_normalized_words(str, search->allocator, words);
+ search->items.append({search->allocator.construct_array_copy(words.as_span()), user_data});
+}
+
+/**
+ * Filter and sort all previously added search items.
+ * Returns an array containing the filtered user data.
+ * The caller has to free the returned array.
+ */
+int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data)
+{
+ using namespace blender;
+
+ LinearAllocator<> allocator;
+ Vector<StringRef, 64> query_words;
+ string_search::extract_normalized_words(query, allocator, query_words);
+
+ /* Compute score of every result. */
+ MultiValueMap<int, int> result_indices_by_score;
+ for (const int result_index : search->items.index_range()) {
+ const int score = string_search::score_query_against_words(
+ query_words, search->items[result_index].normalized_words);
+ if (score >= 0) {
+ result_indices_by_score.add(score, result_index);
+ }
+ }
+
+ Vector<int> found_scores;
+ for (const int score : result_indices_by_score.keys()) {
+ found_scores.append(score);
+ }
+ std::sort(found_scores.begin(), found_scores.end(), std::greater<int>());
+
+ /* Add results to output vector in correct order. First come the results with the best match
+ * score. Results with the same score are in the order they have been added to the search. */
+ Vector<int> sorted_result_indices;
+ for (const int score : found_scores) {
+ Span<int> indices = result_indices_by_score.lookup(score);
+ sorted_result_indices.extend(indices);
+ }
+
+ void **sorted_data = static_cast<void **>(
+ MEM_malloc_arrayN(static_cast<size_t>(sorted_result_indices.size()), sizeof(void *), AT));
+ for (const int i : sorted_result_indices.index_range()) {
+ const int result_index = sorted_result_indices[i];
+ SearchItem &item = search->items[result_index];
+ sorted_data[i] = item.user_data;
+ }
+
+ *r_data = sorted_data;
+
+ return sorted_result_indices.size();
+}
+
+void BLI_string_search_free(StringSearch *string_search)
+{
+ delete string_search;
+}
diff --git a/source/blender/blenlib/tests/BLI_string_search_test.cc b/source/blender/blenlib/tests/BLI_string_search_test.cc
new file mode 100644
index 00000000000..0d1fd2cab96
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_string_search_test.cc
@@ -0,0 +1,50 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_array.hh"
+#include "BLI_string_search.h"
+#include "BLI_vector.hh"
+
+namespace blender::string_search::tests {
+
+TEST(string_search, damerau_levenshtein_distance)
+{
+ EXPECT_EQ(damerau_levenshtein_distance("test", "test"), 0);
+ EXPECT_EQ(damerau_levenshtein_distance("hello", "ell"), 2);
+ EXPECT_EQ(damerau_levenshtein_distance("hello", "hel"), 2);
+ EXPECT_EQ(damerau_levenshtein_distance("ell", "hello"), 2);
+ EXPECT_EQ(damerau_levenshtein_distance("hell", "hello"), 1);
+ EXPECT_EQ(damerau_levenshtein_distance("hello", "hallo"), 1);
+ EXPECT_EQ(damerau_levenshtein_distance("test", ""), 4);
+ EXPECT_EQ(damerau_levenshtein_distance("", "hello"), 5);
+ EXPECT_EQ(damerau_levenshtein_distance("Test", "test"), 1);
+ EXPECT_EQ(damerau_levenshtein_distance("ab", "ba"), 1);
+ EXPECT_EQ(damerau_levenshtein_distance("what", "waht"), 1);
+ EXPECT_EQ(damerau_levenshtein_distance("what", "ahwt"), 2);
+}
+
+TEST(string_search, get_fuzzy_match_errors)
+{
+ EXPECT_EQ(get_fuzzy_match_errors("a", "b"), -1);
+ EXPECT_EQ(get_fuzzy_match_errors("", "abc"), 0);
+ EXPECT_EQ(get_fuzzy_match_errors("hello", "hallo"), 1);
+ EXPECT_EQ(get_fuzzy_match_errors("hap", "hello"), -1);
+ EXPECT_EQ(get_fuzzy_match_errors("armature", "â–¶restore"), -1);
+}
+
+TEST(string_search, extract_normalized_words)
+{
+ LinearAllocator<> allocator;
+ Vector<StringRef, 64> words;
+ extract_normalized_words("hello worldâ–¶test another testâ–¶ 3", allocator, words);
+ EXPECT_EQ(words.size(), 6);
+ EXPECT_EQ(words[0], "hello");
+ EXPECT_EQ(words[1], "world");
+ EXPECT_EQ(words[2], "test");
+ EXPECT_EQ(words[3], "another");
+ EXPECT_EQ(words[4], "test");
+ EXPECT_EQ(words[5], "3");
+}
+
+} // namespace blender::string_search::tests
diff --git a/source/blender/blenlib/tests/BLI_vector_set_test.cc b/source/blender/blenlib/tests/BLI_vector_set_test.cc
index 8f3db8d8403..320cb15f450 100644
--- a/source/blender/blenlib/tests/BLI_vector_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_set_test.cc
@@ -1,5 +1,6 @@
/* Apache License, Version 2.0 */
+#include "BLI_exception_safety_test_utils.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector_set.hh"
#include "testing/testing.h"
@@ -161,4 +162,74 @@ TEST(vector_set, Remove)
EXPECT_FALSE(set.contains(5));
}
+TEST(vector_set, SpanConstructorExceptions)
+{
+ std::array<ExceptionThrower, 5> array = {1, 2, 3, 4, 5};
+ array[3].throw_during_copy = true;
+ Span<ExceptionThrower> span = array;
+
+ EXPECT_ANY_THROW({ VectorSet<ExceptionThrower> set(span); });
+}
+
+TEST(vector_set, CopyConstructorExceptions)
+{
+ VectorSet<ExceptionThrower> set = {1, 2, 3, 4, 5};
+ set[3].throw_during_copy = true;
+
+ EXPECT_ANY_THROW({ VectorSet<ExceptionThrower> set_copy(set); });
+}
+
+TEST(vector_set, MoveConstructorExceptions)
+{
+ VectorSet<ExceptionThrower> set = {1, 2, 3, 4, 5};
+ set[3].throw_during_copy = true;
+ set[3].throw_during_move = true;
+ /* Currently never throws on move, because values are separately allocated. */
+ VectorSet<ExceptionThrower> set_moved(std::move(set));
+ EXPECT_EQ(set.size(), 0); /* NOLINT: bugprone-use-after-move */
+ set.add_multiple({4, 5, 6, 7, 8});
+ EXPECT_EQ(set.size(), 5);
+}
+
+TEST(vector_set, AddNewExceptions)
+{
+ VectorSet<ExceptionThrower> set;
+ ExceptionThrower value;
+ value.throw_during_copy = true;
+ EXPECT_ANY_THROW({ set.add_new(value); });
+ EXPECT_EQ(set.size(), 0);
+ EXPECT_ANY_THROW({ set.add_new(value); });
+ EXPECT_EQ(set.size(), 0);
+}
+
+TEST(vector_set, AddExceptions)
+{
+ VectorSet<ExceptionThrower> set;
+ ExceptionThrower value;
+ value.throw_during_copy = true;
+ EXPECT_ANY_THROW({ set.add(value); });
+ EXPECT_EQ(set.size(), 0);
+ EXPECT_ANY_THROW({ set.add(value); });
+ EXPECT_EQ(set.size(), 0);
+}
+
+TEST(vector_set, ReserveExceptions)
+{
+ VectorSet<ExceptionThrower> set;
+ set.add_multiple({1, 2, 3, 4, 5});
+ set[2].throw_during_move = true;
+ EXPECT_ANY_THROW({ set.reserve(100); });
+}
+
+TEST(vector_set, PopExceptions)
+{
+ VectorSet<ExceptionThrower> set = {1, 2, 3};
+ set.as_span().last().throw_during_move = true;
+ EXPECT_EQ(set.size(), 3);
+ EXPECT_ANY_THROW({ set.pop(); }); /* NOLINT: bugprone-throw-keyword-missing */
+ EXPECT_EQ(set.size(), 3);
+ set.add(10);
+ EXPECT_EQ(set.size(), 4);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c9e837eb3b5..4571e50dd36 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -138,33 +138,77 @@ void BLO_blendhandle_close(BlendHandle *bh);
bool BLO_has_bfile_extension(const char *str);
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
-/* Options controlling behavior of append/link code.
- * Note: merged with 'user-level' options from operators etc. in 16 lower bits
- * (see eFileSel_Params_Flag in DNA_space_types.h). */
-typedef enum BLO_LibLinkFlags {
- /* Generate a placeholder (empty ID) if not found in current lib file. */
+/* -------------------------------------------------------------------- */
+/** \name BLO Blend File Linking API
+ * \{ */
+
+/**
+ * Options controlling behavior of append/link code.
+ * \note merged with 'user-level' options from operators etc. in 16 lower bits
+ * (see #eFileSel_Params_Flag in DNA_space_types.h).
+ */
+typedef enum eBLOLibLinkFlags {
+ /** Generate a placeholder (empty ID) if not found in current lib file. */
BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16,
- /* Force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only). */
+ /** Force loaded ID to be tagged as #LIB_TAG_INDIRECT (used in reload context only). */
BLO_LIBLINK_FORCE_INDIRECT = 1 << 17,
-} BLO_LinkFlags;
+ /**
+ * When set, tag ID types that pass the internal check #library_link_idcode_needs_tag_check
+ *
+ * Currently this is only used to instantiate objects in the scene.
+ * Set this from #BLO_library_link_params_init_with_context so callers
+ * don't need to remember to set this flag.
+ */
+ BLO_LIBLINK_NEEDS_ID_TAG_DOIT = 1 << 18,
+} eBLOLibLinkFlags;
+
+/**
+ * Struct for passing arguments to
+ * #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end.
+ * Wrap these in parameters since it's important both functions receive matching values.
+ */
+struct LibraryLink_Params {
+ /** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */
+ struct Main *bmain;
+ /** Options for linking, used for instantiating. */
+ int flag;
+ /** Context for instancing objects (optional, no instantiation will be performed when NULL). */
+ struct {
+ /** The scene in which to instantiate objects/collections. */
+ struct Scene *scene;
+ /** The scene layer in which to instantiate objects/collections. */
+ struct ViewLayer *view_layer;
+ /** The active 3D viewport (only used to define local-view). */
+ const struct View3D *v3d;
+ } context;
+};
-struct Main *BLO_library_link_begin(struct Main *mainvar, BlendHandle **bh, const char *filepath);
+void BLO_library_link_params_init(struct LibraryLink_Params *params,
+ struct Main *bmain,
+ const int flag);
+void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
+ struct Main *bmain,
+ const int flag,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ const struct View3D *v3d);
+
+struct Main *BLO_library_link_begin(BlendHandle **bh,
+ const char *filepath,
+ const struct LibraryLink_Params *params);
struct ID *BLO_library_link_named_part(struct Main *mainl,
BlendHandle **bh,
const short idcode,
- const char *name);
-struct ID *BLO_library_link_named_part_ex(
- struct Main *mainl, BlendHandle **bh, const short idcode, const char *name, const int flag);
+ const char *name,
+ const struct LibraryLink_Params *params);
void BLO_library_link_end(struct Main *mainl,
BlendHandle **bh,
- int flag,
- struct Main *bmain,
- struct Scene *scene,
- struct ViewLayer *view_layer,
- const struct View3D *v3d);
+ const struct LibraryLink_Params *params);
int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64_t id_types_mask);
+/** \} */
+
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
/* internal function but we need to expose it */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 1b2084d668e..0d77965306f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -262,6 +262,7 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static void direct_link_modifiers(BlendDataReader *reader, ListBase *lb, Object *ob);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
+static bool library_link_idcode_needs_tag_check(const short idcode, const int flag);
#ifdef USE_COLLECTION_COMPAT_28
static void expand_scene_collection(BlendExpander *expander, SceneCollection *sc);
@@ -10318,10 +10319,10 @@ static void add_loose_objects_to_scene(Main *mainvar,
base->local_view_bits |= v3d->local_view_uuid;
}
- if (flag & FILE_AUTOSELECT) {
- base->flag |= BASE_SELECTED;
+ if ((flag & FILE_AUTOSELECT) && (base->flag & BASE_SELECTABLE)) {
/* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it on src/ level. */
+ * if you want it do it at the editor level. */
+ base->flag |= BASE_SELECTED;
}
BKE_scene_object_base_flag_sync_from_base(base);
@@ -10334,6 +10335,62 @@ static void add_loose_objects_to_scene(Main *mainvar,
}
}
+static void add_loose_object_data_to_scene(Main *mainvar,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const View3D *v3d,
+ const short flag)
+{
+ if ((flag & FILE_OBDATA_INSTANCE) == 0) {
+ return;
+ }
+
+ Collection *active_collection = scene->master_collection;
+ if (flag & FILE_ACTIVE_COLLECTION) {
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ active_collection = lc->collection;
+ }
+
+ /* Loop over all ID types, instancing object-data for ID types that have support for it. */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int i = set_listbasepointers(mainvar, lbarray);
+ while (i--) {
+ const short idcode = BKE_idtype_idcode_from_index(i);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (ID *, id, lbarray[i]) {
+ if (id->tag & LIB_TAG_DOIT) {
+ const int type = BKE_object_obdata_to_type(id);
+ BLI_assert(type != -1);
+ Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
+ ob->data = id;
+ id_us_plus(id);
+ BKE_object_materials_test(bmain, ob, ob->data);
+
+ BKE_collection_object_add(bmain, active_collection, ob);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (v3d != NULL) {
+ base->local_view_bits |= v3d->local_view_uuid;
+ }
+
+ if ((flag & FILE_AUTOSELECT) && (base->flag & BASE_SELECTABLE)) {
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ base->flag |= BASE_SELECTED;
+ }
+
+ BKE_scene_object_base_flag_sync_from_base(base);
+
+ copy_v3_v3(ob->loc, scene->cursor.location);
+ }
+ }
+ }
+}
+
static void add_collections_to_scene(Main *mainvar,
Main *bmain,
Scene *scene,
@@ -10350,7 +10407,7 @@ static void add_collections_to_scene(Main *mainvar,
/* Give all objects which are tagged a base. */
LISTBASE_FOREACH (Collection *, collection, &mainvar->collections) {
- if ((flag & FILE_GROUP_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) {
+ if ((flag & FILE_COLLECTION_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) {
/* Any indirect collection should not have been tagged. */
BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0);
@@ -10366,13 +10423,16 @@ static void add_collections_to_scene(Main *mainvar,
base->local_view_bits |= v3d->local_view_uuid;
}
- if (base->flag & BASE_SELECTABLE) {
+ if ((flag & FILE_AUTOSELECT) && (base->flag & BASE_SELECTABLE)) {
base->flag |= BASE_SELECTED;
}
BKE_scene_object_base_flag_sync_from_base(base);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- view_layer->basact = base;
+
+ if (flag & FILE_AUTOSELECT) {
+ view_layer->basact = base;
+ }
/* Assign the collection. */
ob->instance_collection = collection;
@@ -10476,6 +10536,14 @@ static ID *link_named_part(
/* if we found the id but the id is NULL, this is really bad */
BLI_assert(!((bhead != NULL) && (id == NULL)));
+ /* Tag as loose object (or data associated with objects)
+ * needing to be instantiated in #LibraryLink_Params.scene. */
+ if ((id != NULL) && (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
+ if (library_link_idcode_needs_tag_check(idcode, flag)) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ }
+
return id;
}
@@ -10521,23 +10589,6 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_t
return num_directly_linked;
}
-static ID *link_named_part_ex(
- Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
-{
- ID *id = link_named_part(mainl, fd, idcode, name, flag);
-
- if (id && (GS(id->name) == ID_OB)) {
- /* Tag as loose object needing to be instantiated somewhere... */
- id->tag |= LIB_TAG_DOIT;
- }
- else if (id && (GS(id->name) == ID_GR)) {
- /* tag as needing to be instantiated or linked */
- id->tag |= LIB_TAG_DOIT;
- }
-
- return id;
-}
-
/**
* Link a named data-block from an external blend file.
*
@@ -10550,41 +10601,58 @@ static ID *link_named_part_ex(
ID *BLO_library_link_named_part(Main *mainl,
BlendHandle **bh,
const short idcode,
- const char *name)
+ const char *name,
+ const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return link_named_part(mainl, fd, idcode, name, 0);
+ return link_named_part(mainl, fd, idcode, name, params->flag);
}
+/* common routine to append/link something from a library */
+
/**
- * Link a named data-block from an external blend file.
- * Optionally instantiate the object/collection in the scene when the flags are set.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle.
- * \param idcode: The kind of data-block to link.
- * \param name: The name of the data-block (without the 2 char ID prefix).
- * \param flag: Options for linking, used for instantiating.
- * \return the linked ID when found.
+ * Checks if the \a idcode needs to be tagged with #LIB_TAG_DOIT when linking/appending.
*/
-ID *BLO_library_link_named_part_ex(
- Main *mainl, BlendHandle **bh, const short idcode, const char *name, const int flag)
+static bool library_link_idcode_needs_tag_check(const short idcode, const int flag)
{
- FileData *fd = (FileData *)(*bh);
- return link_named_part_ex(mainl, fd, idcode, name, flag);
+ if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
+ /* Always true because of #add_loose_objects_to_scene & #add_collections_to_scene. */
+ if (ELEM(idcode, ID_OB, ID_GR)) {
+ return true;
+ }
+ if (flag & FILE_OBDATA_INSTANCE) {
+ if (OB_DATA_SUPPORT_ID(idcode)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
-/* common routine to append/link something from a library */
+/**
+ * Clears #LIB_TAG_DOIT based on the result of #library_link_idcode_needs_tag_check.
+ */
+static void library_link_clear_tag(Main *mainvar, const int flag)
+{
+ for (int i = 0; i < MAX_LIBARRAY; i++) {
+ const short idcode = BKE_idtype_idcode_from_index(i);
+ BLI_assert(idcode != -1);
+ if (library_link_idcode_needs_tag_check(idcode, flag)) {
+ BKE_main_id_tag_idcode(mainvar, idcode, LIB_TAG_DOIT, false);
+ }
+ }
+}
-static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath)
+static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath, const int flag)
{
Main *mainl;
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- /* clear for objects and collections instantiating tag */
- BKE_main_id_tag_listbase(&(mainvar->objects), LIB_TAG_DOIT, false);
- BKE_main_id_tag_listbase(&(mainvar->collections), LIB_TAG_DOIT, false);
+ if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
+ /* Clear for objects and collections instantiating tag. */
+ library_link_clear_tag(mainvar, flag);
+ }
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@@ -10602,19 +10670,49 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa
return mainl;
}
+void BLO_library_link_params_init(struct LibraryLink_Params *params,
+ struct Main *bmain,
+ const int flag)
+{
+ memset(params, 0, sizeof(*params));
+ params->bmain = bmain;
+ params->flag = flag;
+}
+
+void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
+ struct Main *bmain,
+ const int flag,
+ /* Context arguments. */
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ const struct View3D *v3d)
+{
+ BLO_library_link_params_init(params, bmain, flag);
+ if (scene != NULL) {
+ /* Tagging is needed for instancing. */
+ params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
+
+ params->context.scene = scene;
+ params->context.view_layer = view_layer;
+ params->context.v3d = v3d;
+ }
+}
+
/**
* Initialize the #BlendHandle for linking library data.
*
- * \param mainvar: The current main database, e.g. #G_MAIN or #CTX_data_main(C).
* \param bh: A blender file handle as returned by
* #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
* \param filepath: Used for relative linking, copied to the `lib->filepath`.
- * \return the library #Main, to be passed to #BLO_library_link_named_part_ex as \a mainl.
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
*/
-Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepath)
+Main *BLO_library_link_begin(BlendHandle **bh,
+ const char *filepath,
+ const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return library_link_begin(mainvar, &fd, filepath);
+ return library_link_begin(params->bmain, &fd, filepath, params->flag);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
@@ -10649,8 +10747,8 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
*/
static void library_link_end(Main *mainl,
FileData **fd,
- const short flag,
Main *bmain,
+ const int flag,
Scene *scene,
ViewLayer *view_layer,
const View3D *v3d)
@@ -10727,19 +10825,19 @@ static void library_link_end(Main *mainl,
/* Give a base to loose objects and collections.
* Only directly linked objects & collections are instantiated by
- * #BLO_library_link_named_part_ex & co,
+ * #BLO_library_link_named_part & co,
* here we handle indirect ones and other possible edge-cases. */
- if (scene) {
- add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- }
- else {
- /* printf("library_append_end, scene is NULL (objects wont get bases)\n"); */
- }
+ if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
+ /* Should always be true. */
+ if (scene != NULL) {
+ add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
+ add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
+ add_loose_object_data_to_scene(mainvar, bmain, scene, view_layer, v3d, flag);
+ }
- /* Clear objects and collections instantiating tag. */
- BKE_main_id_tag_listbase(&(mainvar->objects), LIB_TAG_DOIT, false);
- BKE_main_id_tag_listbase(&(mainvar->collections), LIB_TAG_DOIT, false);
+ /* Clear objects and collections instantiating tag. */
+ library_link_clear_tag(mainvar, flag);
+ }
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
@@ -10755,25 +10853,18 @@ static void library_link_end(Main *mainl,
*
* \param mainl: The main database to link from (not the active one).
* \param bh: The blender file handle (WARNING! may be freed by this function!).
- * \param flag: Options for linking, used for instantiating.
- * \param bmain: The main database in which to instantiate objects/collections
- * \param scene: The scene in which to instantiate objects/collections
- * (if NULL, no instantiation is done).
- * \param view_layer: The scene layer in which to instantiate objects/collections
- * (if NULL, no instantiation is done).
- * \param v3d: The active 3D viewport
- * (only to define local-view for instantiated objects & groups, can be NULL).
+ * \param params: Settings for linking that don't change from beginning to end of linking.
*/
-void BLO_library_link_end(Main *mainl,
- BlendHandle **bh,
- int flag,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
+void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- library_link_end(mainl, &fd, flag, bmain, scene, view_layer, v3d);
+ library_link_end(mainl,
+ &fd,
+ params->bmain,
+ params->flag,
+ params->context.scene,
+ params->context.view_layer,
+ params->context.v3d);
*bh = (BlendHandle *)fd;
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 2018cf24ce6..ecc735700ea 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -2975,10 +2975,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
UnitSettings *unit = &scene->unit;
if (unit->system != USER_UNIT_NONE) {
- unit->length_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_LENGTH);
- unit->mass_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_MASS);
+ unit->length_unit = BKE_unit_base_of_type_get(scene->unit.system, B_UNIT_LENGTH);
+ unit->mass_unit = BKE_unit_base_of_type_get(scene->unit.system, B_UNIT_MASS);
}
- unit->time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_NONE, B_UNIT_TIME);
+ unit->time_unit = BKE_unit_base_of_type_get(USER_UNIT_NONE, B_UNIT_TIME);
}
/* gpencil grid settings */
@@ -3422,7 +3422,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
SpaceFile *sfile = (SpaceFile *)sl;
if (sfile->params) {
sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_6 |
- FILE_PARAMS_FLAG_UNUSED_9);
+ FILE_OBDATA_INSTANCE);
}
break;
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 66dc75e0fdf..6aa7de06277 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -513,6 +513,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (md->type == eModifierType_Boolean) {
BooleanModifierData *bmd = (BooleanModifierData *)md;
bmd->solver = eBooleanModifierSolver_Fast;
+ bmd->flag = 0;
}
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index f3616460d8f..a0245346771 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -3270,17 +3270,31 @@ static void write_workspace(BlendWriter *writer, WorkSpace *workspace, const voi
static void write_hair(BlendWriter *writer, Hair *hair, const void *id_address)
{
if (hair->id.us > 0 || BLO_write_is_undo(writer)) {
+ CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
+
/* Write LibData */
BLO_write_id_struct(writer, Hair, id_address, &hair->id);
BKE_id_blend_write(writer, &hair->id);
/* Direct data */
- CustomData_blend_write(writer, &hair->pdata, hair->totpoint, CD_MASK_ALL, &hair->id);
- CustomData_blend_write(writer, &hair->cdata, hair->totcurve, CD_MASK_ALL, &hair->id);
+ CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id);
+ CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id);
+
BLO_write_pointer_array(writer, hair->totcol, hair->mat);
if (hair->adt) {
BKE_animdata_blend_write(writer, hair->adt);
}
+
+ /* Remove temporary data. */
+ if (players && players != players_buff) {
+ MEM_freeN(players);
+ }
+ if (clayers && clayers != clayers_buff) {
+ MEM_freeN(clayers);
+ }
}
}
@@ -3288,7 +3302,7 @@ static void write_pointcloud(BlendWriter *writer, PointCloud *pointcloud, const
{
if (pointcloud->id.us > 0 || BLO_write_is_undo(writer)) {
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_file_write_prepare(
+ CustomData_blend_write_prepare(
&pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
/* Write LibData */
@@ -3297,7 +3311,8 @@ static void write_pointcloud(BlendWriter *writer, PointCloud *pointcloud, const
/* Direct data */
CustomData_blend_write(
- writer, &pointcloud->pdata, pointcloud->totpoint, CD_MASK_ALL, &pointcloud->id);
+ writer, &pointcloud->pdata, players, pointcloud->totpoint, CD_MASK_ALL, &pointcloud->id);
+
BLO_write_pointer_array(writer, pointcloud->totcol, pointcloud->mat);
if (pointcloud->adt) {
BKE_animdata_blend_write(writer, pointcloud->adt);
@@ -3356,13 +3371,24 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const
/* TODO: Decentralize this part. */
if (STREQ(state->type, SIM_TYPE_NAME_PARTICLE_SIMULATION)) {
ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
+
+ CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
+ CustomData_blend_write_prepare(
+ &particle_state->attributes, &players, players_buff, ARRAY_SIZE(players_buff));
+
BLO_write_struct(writer, ParticleSimulationState, particle_state);
CustomData_blend_write(writer,
&particle_state->attributes,
+ players,
particle_state->tot_particles,
CD_MASK_ALL,
&simulation->id);
+
+ /* Remove temporary data. */
+ if (players && players != players_buff) {
+ MEM_freeN(players);
+ }
}
else if (STREQ(state->type, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER)) {
ParticleMeshEmitterSimulationState *emitter_state = (ParticleMeshEmitterSimulationState *)
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index 5d410d60496..d2f73dd63ec 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -340,8 +340,8 @@ static bool bmesh_boolean(BMesh *bm,
IMesh m_in = mesh_from_bm(bm, looptris, looptris_tot, &m_triangulated, &arena);
std::function<int(int)> shape_fn;
int nshapes;
- if (use_self) {
- /* Unary boolean operation. Want every face where test_fn doesn't return -1. */
+ if (use_self && boolean_mode == BoolOpType::None) {
+ /* Unary knife operation. Want every face where test_fn doesn't return -1. */
nshapes = 1;
shape_fn = [bm, test_fn, user_data](int f) {
BMFace *bmf = BM_face_at_index(bm, f);
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 2e0487bfca1..2c4b7f03db5 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -20,7 +20,7 @@
/** \file
* \ingroup depsgraph
*
- * Evaluation engine entrypoints for Depsgraph Engine.
+ * Evaluation engine entry-points for Depsgraph Engine.
*/
#include "intern/eval/deg_eval.h"
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
index 49690f15412..7a23c0f8613 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -20,7 +20,7 @@
/** \file
* \ingroup depsgraph
*
- * Evaluation engine entrypoints for Depsgraph Engine.
+ * Evaluation engine entry-points for Depsgraph Engine.
*/
#pragma once
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index b299df50852..8aea2f8e969 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -437,9 +437,9 @@ if(WITH_GTESTS)
)
set(TEST_INC
"../../../intern/ghost/"
+ "../gpu/tests/"
)
set(TEST_LIB
- bf_draw
)
include(GTestTesting)
blender_add_test_lib(bf_draw_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 2bd1a875371..3b2a3cc7c01 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -26,7 +26,7 @@
#include "BKE_global.h" /* for G.debug_value */
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_platform.h"
#include "GPU_state.h"
#include "GPU_texture.h"
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 49d68481045..f23cca41215 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -41,8 +41,8 @@
#include "eevee_lightcache.h"
#include "eevee_private.h"
+#include "GPU_capabilities.h"
#include "GPU_context.h"
-#include "GPU_extensions.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -348,17 +348,14 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
int mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL;
- if (GPU_arb_texture_cube_map_array_is_supported()) {
- light_cache->cube_tx.tex = DRW_texture_create_cube_array(
- cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
- }
- else {
- light_cache->cube_tx.tex = DRW_texture_create_2d_array(cube_size,
- cube_size,
- cube_len * 6,
- GPU_R11F_G11F_B10F,
- DRW_TEX_FILTER | DRW_TEX_MIPMAP,
- NULL);
+ /* Try to create a cubemap array. */
+ DRWTextureFlag cube_texflag = DRW_TEX_FILTER | DRW_TEX_MIPMAP;
+ light_cache->cube_tx.tex = DRW_texture_create_cube_array(
+ cube_size, cube_len, GPU_R11F_G11F_B10F, cube_texflag, NULL);
+ if (light_cache->cube_tx.tex == NULL) {
+ /* Try fallback to 2D array. */
+ light_cache->cube_tx.tex = DRW_texture_create_2d_array(
+ cube_size, cube_size, cube_len * 6, GPU_R11F_G11F_B10F, cube_texflag, NULL);
}
light_cache->cube_tx.tex_size[0] = cube_size;
@@ -414,15 +411,16 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
}
if (lcache->cube_tx.tex == NULL) {
- if (GPU_arb_texture_cube_map_array_is_supported()) {
- lcache->cube_tx.tex = GPU_texture_create_cube_array("lightcache_cubemaps",
- lcache->cube_tx.tex_size[0],
- lcache->cube_tx.tex_size[2] / 6,
- lcache->mips_len + 1,
- GPU_R11F_G11F_B10F,
- NULL);
- }
- else {
+ /* Try to create a cubemap array. */
+ lcache->cube_tx.tex = GPU_texture_create_cube_array("lightcache_cubemaps",
+ lcache->cube_tx.tex_size[0],
+ lcache->cube_tx.tex_size[2] / 6,
+ lcache->mips_len + 1,
+ GPU_R11F_G11F_B10F,
+ NULL);
+
+ if (lcache->cube_tx.tex == NULL) {
+ /* Try fallback to 2D array. */
lcache->cube_tx.tex = GPU_texture_create_2d_array("lightcache_cubemaps_fallback",
UNPACK3(lcache->cube_tx.tex_size),
lcache->mips_len + 1,
@@ -528,7 +526,7 @@ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
if (lbake->gl_context) {
DRW_opengl_render_context_enable(lbake->gl_context);
if (lbake->gpu_context == NULL) {
- lbake->gpu_context = GPU_context_create(0);
+ lbake->gpu_context = GPU_context_create(NULL);
}
DRW_gpu_render_context_enable(lbake->gpu_context);
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 9f86958cef8..89e61ab939a 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -36,7 +36,7 @@
#include "BKE_object.h"
#include "MEM_guardedalloc.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_material.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index b7b765d9c00..3c684c467a4 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -32,7 +32,7 @@
#include "eevee_private.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_platform.h"
#include "GPU_state.h"
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 2351b06db98..504e4e1d336 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -38,7 +38,7 @@
#include "DEG_depsgraph_query.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_state.h"
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index bbc5801b0f7..d4b1d421603 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -32,7 +32,7 @@
#include "MEM_guardedalloc.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_material.h"
#include "GPU_shader.h"
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 58b545be2f5..f9195e5861d 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -28,7 +28,7 @@
#include "DEG_depsgraph_query.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_material.h"
#include "GPU_texture.h"
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 85c7c89934c..69b916244b5 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -44,7 +44,7 @@
#include "DEG_depsgraph_query.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_material.h"
#include "GPU_texture.h"
#include "eevee_private.h"
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 5d417d995ac..b18013d742a 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -182,6 +182,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
+ GPU_DATA_FLOAT,
rp->rect);
float winmat[4][4];
diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c
index 738f4a67471..9fdefed019f 100644
--- a/source/blender/draw/engines/workbench/workbench_opaque.c
+++ b/source/blender/draw/engines/workbench/workbench_opaque.c
@@ -31,8 +31,6 @@
#include "DRW_render.h"
-#include "GPU_extensions.h"
-
#include "workbench_engine.h"
#include "workbench_private.h"
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 8760f2651ee..2c3b5a5f935 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -124,6 +124,7 @@ static void workbench_render_result_z(struct RenderLayer *rl,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
+ GPU_DATA_FLOAT,
rp->rect);
float winmat[4][4];
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
index 5eff056846c..1c8575ddc12 100644
--- a/source/blender/draw/engines/workbench/workbench_transparent.c
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -35,8 +35,6 @@
#include "ED_view3d.h"
-#include "GPU_extensions.h"
-
#include "workbench_engine.h"
#include "workbench_private.h"
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 680636f9e87..e154a52b32f 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -721,7 +721,6 @@ void DRW_state_lock(DRWState state);
void DRW_select_load_id(uint id);
/* Draw State */
-void DRW_state_dfdy_factors_get(float dfdyfac[2]);
bool DRW_state_is_fbo(void);
bool DRW_state_is_select(void);
bool DRW_state_is_depth(void);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index 9f4ae8fbfbf..cb716b3130a 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -59,7 +59,7 @@
#include "bmesh.h"
#include "GPU_batch.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "DRW_render.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
index 2f7ce54aef4..42e410ad189 100644
--- a/source/blender/draw/intern/draw_cache_impl_displist.c
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -37,7 +37,7 @@
#include "BKE_displist_tangent.h"
#include "GPU_batch.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "draw_cache_inline.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index e8a712b6881..c7ba707d403 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -169,7 +169,7 @@ static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_us
static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = editmesh_final_or_this(me);
- const CustomData *cd_ldata = &me_final->ldata;
+ const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
if (layer != -1) {
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 09ce16efcc2..e6d51bce54e 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -64,7 +64,7 @@
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -2496,11 +2496,6 @@ void DRW_draw_depth_object(
/** \name Draw Manager State (DRW_state)
* \{ */
-void DRW_state_dfdy_factors_get(float dfdyfac[2])
-{
- GPU_get_dfdy_factors(dfdyfac);
-}
-
/**
* When false, drawing doesn't output to a pixel buffer
* eg: Occlusion queries, or when we have setup a context to draw in already.
@@ -2772,17 +2767,11 @@ void DRW_opengl_context_create(void)
BLI_assert(DST.gl_context == NULL); /* Ensure it's called once */
DST.gl_context_mutex = BLI_ticket_mutex_alloc();
- if (!G.background) {
- immDeactivate();
- }
/* This changes the active context. */
DST.gl_context = WM_opengl_context_create();
WM_opengl_context_activate(DST.gl_context);
/* Be sure to create gpu_context too. */
- DST.gpu_context = GPU_context_create(0);
- if (!G.background) {
- immActivate();
- }
+ DST.gpu_context = GPU_context_create(NULL);
/* So we activate the window's one afterwards. */
wm_window_reset_drawable();
}
@@ -2799,25 +2788,15 @@ void DRW_opengl_context_destroy(void)
}
}
-void DRW_opengl_context_enable_ex(bool restore)
+void DRW_opengl_context_enable_ex(bool UNUSED(restore))
{
if (DST.gl_context != NULL) {
/* IMPORTANT: We dont support immediate mode in render mode!
* This shall remain in effect until immediate mode supports
* multiple threads. */
BLI_ticket_mutex_lock(DST.gl_context_mutex);
- if (BLI_thread_is_main() && restore) {
- if (!G.background) {
- immDeactivate();
- }
- }
WM_opengl_context_activate(DST.gl_context);
GPU_context_active_set(DST.gpu_context);
- if (BLI_thread_is_main() && restore) {
- if (!G.background) {
- immActivate();
- }
- }
}
}
@@ -2867,7 +2846,6 @@ void DRW_opengl_render_context_enable(void *re_gl_context)
void DRW_opengl_render_context_disable(void *re_gl_context)
{
- GPU_flush();
WM_opengl_context_release(re_gl_context);
/* TODO get rid of the blocking. */
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
@@ -2885,6 +2863,7 @@ void DRW_gpu_render_context_enable(void *re_gpu_context)
/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context))
{
+ GPU_flush();
GPU_context_active_set(NULL);
}
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 58464c0a15a..79d74e1f67d 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -29,7 +29,6 @@
#include "BKE_global.h"
-#include "GPU_extensions.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
#include "GPU_state.h"
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 7602bbb39ac..85c04b73529 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -29,18 +29,21 @@
#include "BLI_string_utils.h"
#include "BLI_threads.h"
+#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "DEG_depsgraph_query.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "wm_window.h"
+
#include "draw_manager.h"
extern char datatoc_gpu_shader_2D_vert_glsl[];
@@ -73,6 +76,7 @@ typedef struct DRWShaderCompiler {
ThreadMutex compilation_lock;
void *gl_context;
+ GPUContext *gpu_context;
bool own_context;
int shaders_done; /* To compute progress. */
@@ -102,10 +106,10 @@ static void drw_deferred_shader_compilation_exec(
{
DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
void *gl_context = comp->gl_context;
+ GPUContext *gpu_context = comp->gpu_context;
-#if TRUST_NO_ONE
BLI_assert(gl_context != NULL);
-#endif
+ BLI_assert(gpu_context != NULL);
const bool use_main_context_workaround = GPU_use_main_context_workaround();
if (use_main_context_workaround) {
@@ -114,6 +118,7 @@ static void drw_deferred_shader_compilation_exec(
}
WM_opengl_context_activate(gl_context);
+ GPU_context_active_set(gpu_context);
while (true) {
BLI_spin_lock(&comp->list_lock);
@@ -160,6 +165,7 @@ static void drw_deferred_shader_compilation_exec(
BLI_spin_unlock(&comp->list_lock);
}
+ GPU_context_active_set(NULL);
WM_opengl_context_release(gl_context);
if (use_main_context_workaround) {
GPU_context_main_unlock();
@@ -188,7 +194,12 @@ static void drw_deferred_shader_compilation_free(void *custom_data)
if (comp->own_context) {
/* Only destroy if the job owns the context. */
+ WM_opengl_context_activate(comp->gl_context);
+ GPU_context_active_set(comp->gpu_context);
+ GPU_context_discard(comp->gpu_context);
WM_opengl_context_dispose(comp->gl_context);
+
+ wm_window_reset_drawable();
}
MEM_freeN(comp);
@@ -238,6 +249,7 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
/* Do not recreate context, just pass ownership. */
if (old_comp->gl_context) {
comp->gl_context = old_comp->gl_context;
+ comp->gpu_context = old_comp->gpu_context;
old_comp->own_context = false;
comp->own_context = job_own_context;
}
@@ -249,10 +261,15 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
if (comp->gl_context == NULL) {
if (use_main_context) {
comp->gl_context = DST.gl_context;
+ comp->gpu_context = DST.gpu_context;
}
else {
comp->gl_context = WM_opengl_context_create();
+ comp->gpu_context = GPU_context_create(NULL);
+ GPU_context_active_set(NULL);
+
WM_opengl_context_activate(DST.gl_context);
+ GPU_context_active_set(DST.gpu_context);
}
comp->own_context = job_own_context;
}
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index b3c4c97715e..adcac15ab85 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -298,13 +298,13 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
}
if (unit->system) {
- numstr_len = bUnit_AsString2(numstr,
- sizeof(numstr),
- len_v3v3(v1, v2) * unit->scale_length,
- 3,
- B_UNIT_LENGTH,
- unit,
- false);
+ numstr_len = BKE_unit_value_as_string(numstr,
+ sizeof(numstr),
+ len_v3v3(v1, v2) * unit->scale_length,
+ 3,
+ B_UNIT_LENGTH,
+ unit,
+ false);
}
else {
numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
@@ -440,13 +440,14 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
mul_m4_v3(ob->obmat, vmid);
if (unit->system) {
- numstr_len = bUnit_AsString2(numstr,
- sizeof(numstr),
- (double)(area * unit->scale_length * unit->scale_length),
- 3,
- B_UNIT_AREA,
- unit,
- false);
+ numstr_len = BKE_unit_value_as_string(
+ numstr,
+ sizeof(numstr),
+ (double)(area * unit->scale_length * unit->scale_length),
+ 3,
+ B_UNIT_AREA,
+ unit,
+ false);
}
else {
numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area);
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index a3a0b792a24..b73c94208b5 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -7,38 +7,22 @@
#include "GPU_context.h"
#include "GPU_init_exit.h"
#include "GPU_shader.h"
-
-#include "GHOST_C-api.h"
+#include "gpu_testing.hh"
#include "engines/eevee/eevee_private.h"
#include "engines/gpencil/gpencil_engine.h"
#include "engines/overlay/overlay_private.h"
#include "engines/workbench/workbench_private.h"
-/* Base class for draw test cases. It will setup and tear down the GPU part around each test. */
-class DrawTest : public ::testing::Test {
- private:
- GHOST_SystemHandle ghost_system;
- GHOST_ContextHandle ghost_context;
- GPUContext *context;
+namespace blender::draw {
+/* Base class for draw test cases. It will setup and tear down the GPU part around each test. */
+class DrawTest : public blender::gpu::GPUTest {
void SetUp() override
{
- GHOST_GLSettings glSettings = {0};
- ghost_system = GHOST_CreateSystem();
- ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings);
- context = GPU_context_create(0);
- GPU_init();
+ GPUTest::SetUp();
DRW_draw_state_init_gtests(GPU_SHADER_CFG_DEFAULT);
}
-
- void TearDown() override
- {
- GPU_exit();
- GPU_context_discard(context);
- GHOST_DisposeOpenGLContext(ghost_system, ghost_context);
- GHOST_DisposeSystem(ghost_system);
- }
};
TEST_F(DrawTest, workbench_glsl_shaders)
@@ -319,4 +303,6 @@ TEST_F(DrawTest, eevee_glsl_shaders_static)
EXPECT_NE(EEVEE_shaders_effect_screen_raytrace_sh_get(ssr_option), nullptr);
}
EEVEE_shaders_free();
-} \ No newline at end of file
+}
+
+} // namespace blender::draw \ No newline at end of file
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index afb92ca7742..586a70d1e9d 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -58,7 +58,7 @@
/* Loops over the gp-frames for a gp-layer, and applies the given callback */
bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
Scene *scene,
- short (*gpf_cb)(bGPDframe *, Scene *))
+ bool (*gpf_cb)(bGPDframe *, Scene *))
{
/* error checker */
if (gpl == NULL) {
@@ -511,40 +511,40 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* -------------------------------------- */
/* Snap Tools */
-static short gpencil_frame_snap_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene))
+static bool gpencil_frame_snap_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene))
{
#if 0 /* note: gpf->framenum is already an int! */
if (gpf->flag & GP_FRAME_SELECT) {
gpf->framenum = (int)(floor(gpf->framenum + 0.5));
}
#endif
- return 0;
+ return false;
}
-static short gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene)
+static bool gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene)
{
float secf = (float)FPS;
if (gpf->flag & GP_FRAME_SELECT) {
gpf->framenum = (int)(floorf(gpf->framenum / secf + 0.5f) * secf);
}
- return 0;
+ return false;
}
-static short gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene)
+static bool gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene)
{
if (gpf->flag & GP_FRAME_SELECT) {
gpf->framenum = (int)CFRA;
}
- return 0;
+ return false;
}
-static short gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
+static bool gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
{
if (gpf->flag & GP_FRAME_SELECT) {
gpf->framenum = (int)ED_markers_find_nearest_marker_time(&scene->markers,
(float)gpf->framenum);
}
- return 0;
+ return false;
}
/* snap selected frames to ... */
@@ -571,7 +571,7 @@ void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
/* -------------------------------------- */
/* Mirror Tools */
-static short gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene)
+static bool gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene)
{
int diff;
@@ -580,10 +580,10 @@ static short gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene)
gpf->framenum = CFRA + diff;
}
- return 0;
+ return false;
}
-static short gpencil_frame_mirror_yaxis(bGPDframe *gpf, Scene *UNUSED(scene))
+static bool gpencil_frame_mirror_yaxis(bGPDframe *gpf, Scene *UNUSED(scene))
{
int diff;
@@ -592,10 +592,10 @@ static short gpencil_frame_mirror_yaxis(bGPDframe *gpf, Scene *UNUSED(scene))
gpf->framenum = diff;
}
- return 0;
+ return false;
}
-static short gpencil_frame_mirror_xaxis(bGPDframe *gpf, Scene *UNUSED(scene))
+static bool gpencil_frame_mirror_xaxis(bGPDframe *gpf, Scene *UNUSED(scene))
{
int diff;
@@ -605,10 +605,10 @@ static short gpencil_frame_mirror_xaxis(bGPDframe *gpf, Scene *UNUSED(scene))
gpf->framenum = diff;
}
- return 0;
+ return false;
}
-static short gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
+static bool gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
{
static TimeMarker *marker;
static short initialized = 0;
@@ -645,7 +645,7 @@ static short gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
}
}
- return 0;
+ return false;
}
/* mirror selected gp-frames on... */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index c84da5517f8..74c23977799 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -176,7 +176,7 @@ void ED_annotation_draw_ex(struct Scene *scene,
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gpencil_layer_frames_looper(struct bGPDlayer *gpl,
struct Scene *scene,
- short (*gpf_cb)(struct bGPDframe *, struct Scene *));
+ bool (*gpf_cb)(struct bGPDframe *, struct Scene *));
void ED_gpencil_layer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel);
bool ED_gpencil_layer_frame_select_check(struct bGPDlayer *gpl);
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 80510d3afa1..f683495608a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -91,8 +91,8 @@ bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame);
/* ----------- Mask AnimEdit API ------------------ */
bool ED_masklayer_frames_looper(struct MaskLayer *mask_layer,
struct Scene *scene,
- short (*mask_layer_shape_cb)(struct MaskLayerShape *,
- struct Scene *));
+ bool (*mask_layer_shape_cb)(struct MaskLayerShape *,
+ struct Scene *));
void ED_masklayer_make_cfra_list(struct MaskLayer *mask_layer, ListBase *elems, bool onlysel);
bool ED_masklayer_frame_select_check(struct MaskLayer *mask_layer);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 8aa9cd8184b..b0ef22575ee 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -323,7 +323,8 @@ void ED_objects_recalculate_paths(struct bContext *C,
eObjectPathCalcRange range);
/* constraints */
-struct ListBase *ED_object_constraint_list_from_context(struct Object *ob);
+struct ListBase *ED_object_constraint_active_list(struct Object *ob);
+struct ListBase *ED_object_pose_constraint_list(const struct bContext *C);
struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob,
struct bConstraint *con,
struct bPoseChannel **r_pchan);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index bbe097b5c79..0bd4934dd0f 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
@@ -2570,7 +2571,7 @@ void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
orig_str = BLI_strdup(str);
- bUnit_ToUnitAltName(str, maxlen, orig_str, unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
+ BKE_unit_name_to_alt(str, maxlen, orig_str, unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
MEM_freeN(orig_str);
}
@@ -2605,13 +2606,13 @@ static void ui_get_but_string_unit(
precision = float_precision;
}
- bUnit_AsString2(str,
- len_max,
- ui_get_but_scale_unit(but, value),
- precision,
- RNA_SUBTYPE_UNIT_VALUE(unit_type),
- unit,
- pad);
+ BKE_unit_value_as_string(str,
+ len_max,
+ ui_get_but_scale_unit(but, value),
+ precision,
+ RNA_SUBTYPE_UNIT_VALUE(unit_type),
+ unit,
+ pad);
}
static float ui_get_but_step_unit(uiBut *but, float step_default)
@@ -2621,12 +2622,13 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
/* Scaling up 'step_origg ' here is a bit arbitrary,
* its just giving better scales from user POV */
const double scale_step = ui_get_but_scale_unit(but, step_orig * 10);
- const double step = bUnit_ClosestScalar(scale_step, but->block->unit->system, unit_type);
+ const double step = BKE_unit_closest_scalar(scale_step, but->block->unit->system, unit_type);
/* -1 is an error value */
if (step != -1.0) {
const double scale_unit = ui_get_but_scale_unit(but, 1.0);
- const double step_unit = bUnit_ClosestScalar(scale_unit, but->block->unit->system, unit_type);
+ const double step_unit = BKE_unit_closest_scalar(
+ scale_unit, but->block->unit->system, unit_type);
double step_final;
BLI_assert(step > 0.0);
@@ -6651,30 +6653,34 @@ static void operator_enum_search_update_fn(const struct bContext *C,
}
else {
PointerRNA *ptr = UI_but_operator_ptr_get(but); /* Will create it if needed! */
- const EnumPropertyItem *item, *item_array;
+
bool do_free;
+ const EnumPropertyItem *all_items;
+ RNA_property_enum_items_gettexted((bContext *)C, ptr, prop, &all_items, NULL, &do_free);
- /* Prepare BLI_string_all_words_matched. */
- const size_t str_len = strlen(str);
- const int words_max = BLI_string_max_possible_word_count(str_len);
- int(*words)[2] = BLI_array_alloca(words, words_max);
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+ StringSearch *search = BLI_string_search_new();
+ for (const EnumPropertyItem *item = all_items; item->identifier; item++) {
+ BLI_string_search_add(search, item->name, (void *)item);
+ }
- RNA_property_enum_items_gettexted((bContext *)C, ptr, prop, &item_array, NULL, &do_free);
+ const EnumPropertyItem **filtered_items;
+ int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
- for (item = item_array; item->identifier; item++) {
+ for (int i = 0; i < filtered_amount; i++) {
+ const EnumPropertyItem *item = filtered_items[i];
/* note: need to give the index rather than the
* identifier because the enum can be freed */
- if (BLI_string_all_words_matched(item->name, str, words, words_len)) {
- if (!UI_search_item_add(
- items, item->name, POINTER_FROM_INT(item->value), item->icon, 0, 0)) {
- break;
- }
+ if (!UI_search_item_add(
+ items, item->name, POINTER_FROM_INT(item->value), item->icon, 0, 0)) {
+ break;
}
}
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+
if (do_free) {
- MEM_freeN((void *)item_array);
+ MEM_freeN((void *)all_items);
}
}
}
@@ -6762,7 +6768,8 @@ void UI_but_number_precision_set(uiBut *but, float precision)
BLI_assert(but->type == UI_BTYPE_NUM);
but_number->precision = precision;
- BLI_assert(precision > -1);
+ /* -1 is a valid value, UI code figures out an appropriate precision then. */
+ BLI_assert(precision > -2);
}
/**
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index fbc0ed1fc1f..ead65a62226 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -193,13 +193,13 @@ static void depthdropper_depth_sample_pt(
*r_depth = len_v3v3(view_co, co_align);
- bUnit_AsString2(ddr->name,
- sizeof(ddr->name),
- (double)*r_depth,
- 4,
- B_UNIT_LENGTH,
- &scene->unit,
- false);
+ BKE_unit_value_as_string(ddr->name,
+ sizeof(ddr->name),
+ (double)*r_depth,
+ 4,
+ B_UNIT_LENGTH,
+ &scene->unit,
+ false);
}
else {
BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index a4042ab8265..6a6914daf47 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -4614,8 +4614,8 @@ static float ui_numedit_apply_snapf(
UnitSettings *unit = but->block->unit;
const int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
- if (bUnit_IsValid(unit->system, unit_type)) {
- fac = (float)bUnit_BaseScalar(unit->system, unit_type);
+ if (BKE_unit_is_valid(unit->system, unit_type)) {
+ fac = (float)BKE_unit_base_scalar(unit->system, unit_type);
if (ELEM(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
fac /= unit->scale_length;
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index cf0bb8d4e8c..5c4877534f6 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -2074,7 +2074,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
* Supposing the block has a panel and isn't a menu, handle opening, closing, pinning, etc.
* Code currently assumes layout style for location of widgets
*
- * \param mx The mouse x coordinate, in panel space.
+ * \param mx: The mouse x coordinate, in panel space.
*/
static void ui_handle_panel_header(const bContext *C,
uiBlock *block,
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 667dcfd935d..5bde51846a8 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -41,6 +41,7 @@
#include "BLI_math_matrix.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@@ -993,19 +994,24 @@ static void menu_search_update_fn(const bContext *UNUSED(C),
{
struct MenuSearch_Data *data = arg;
- /* Prepare BLI_string_all_words_matched. */
- const size_t str_len = strlen(str);
- const int words_max = BLI_string_max_possible_word_count(str_len);
- int(*words)[2] = BLI_array_alloca(words, words_max);
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+ StringSearch *search = BLI_string_search_new();
- for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) {
- if (BLI_string_all_words_matched(item->drawwstr_full, str, words, words_len)) {
- if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
- break;
- }
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ BLI_string_search_add(search, item->drawwstr_full, item);
+ }
+
+ struct MenuSearch_Item **filtered_items;
+ int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
+
+ for (int i = 0; i < filtered_amount; i++) {
+ struct MenuSearch_Item *item = filtered_items[i];
+ if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
+ break;
}
}
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 5fbd26a4f5a..08d3ad0f23c 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -44,6 +44,7 @@
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_timecode.h"
#include "BLI_utildefines.h"
@@ -330,67 +331,61 @@ static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, vo
}
}
-static bool id_search_add(const bContext *C,
- TemplateID *template_ui,
- const int flag,
- const char *str,
- uiSearchItems *items,
- ID *id)
+static bool id_search_allows_id(TemplateID *template_ui, const int flag, ID *id, const char *query)
{
ID *id_from = template_ui->ptr.owner_id;
- if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
+ /* Do self check. */
+ if ((flag & PROP_ID_SELF_CHECK) && id == id_from) {
+ return false;
+ }
- /* use filter */
- if (RNA_property_type(template_ui->prop) == PROP_POINTER) {
- PointerRNA ptr;
- RNA_id_pointer_create(id, &ptr);
- if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) {
- return true;
- }
+ /* Use filter. */
+ if (RNA_property_type(template_ui->prop) == PROP_POINTER) {
+ PointerRNA ptr;
+ RNA_id_pointer_create(id, &ptr);
+ if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) {
+ return false;
}
+ }
- /* hide dot-datablocks, but only if filter does not force it visible */
- if (U.uiflag & USER_HIDE_DOT) {
- if ((id->name[2] == '.') && (str[0] != '.')) {
- return true;
- }
+ /* Hide dot-datablocks, but only if filter does not force them visible. */
+ if (U.uiflag & USER_HIDE_DOT) {
+ if ((id->name[2] == '.') && (query[0] != '.')) {
+ return false;
}
+ }
- /* Prepare BLI_string_all_words_matched. */
- const size_t str_len = strlen(str);
- const int words_max = BLI_string_max_possible_word_count(str_len);
- int(*words)[2] = BLI_array_alloca(words, words_max);
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
-
- if (*str == '\0' || BLI_string_all_words_matched(id->name + 2, str, words, words_len)) {
- /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
- * followed by ID_NAME-2 characters from id->name
- */
- char name_ui[MAX_ID_FULL_NAME_UI];
- int iconid = ui_id_icon_get(C, id, template_ui->preview);
- const bool use_lib_prefix = template_ui->preview || iconid;
- const bool has_sep_char = (id->lib != NULL);
-
- /* When using previews, the library hint (linked, overridden, missing) is added with a
- * character prefix, otherwise we can use a icon. */
- int name_prefix_offset;
- BKE_id_full_name_ui_prefix_get(
- name_ui, id, use_lib_prefix, UI_SEP_CHAR, &name_prefix_offset);
- if (!use_lib_prefix) {
- iconid = UI_library_icon_get(id);
- }
+ return true;
+}
- if (!UI_search_item_add(items,
- name_ui,
- id,
- iconid,
- has_sep_char ? UI_BUT_HAS_SEP_CHAR : 0,
- name_prefix_offset)) {
- return false;
- }
- }
+static bool id_search_add(const bContext *C, TemplateID *template_ui, uiSearchItems *items, ID *id)
+{
+ /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
+ * followed by ID_NAME-2 characters from id->name
+ */
+ char name_ui[MAX_ID_FULL_NAME_UI];
+ int iconid = ui_id_icon_get(C, id, template_ui->preview);
+ const bool use_lib_prefix = template_ui->preview || iconid;
+ const bool has_sep_char = (id->lib != NULL);
+
+ /* When using previews, the library hint (linked, overridden, missing) is added with a
+ * character prefix, otherwise we can use a icon. */
+ int name_prefix_offset;
+ BKE_id_full_name_ui_prefix_get(name_ui, id, use_lib_prefix, UI_SEP_CHAR, &name_prefix_offset);
+ if (!use_lib_prefix) {
+ iconid = UI_library_icon_get(id);
+ }
+
+ if (!UI_search_item_add(items,
+ name_ui,
+ id,
+ iconid,
+ has_sep_char ? UI_BUT_HAS_SEP_CHAR : 0,
+ name_prefix_offset)) {
+ return false;
}
+
return true;
}
@@ -404,12 +399,26 @@ static void id_search_cb(const bContext *C,
ListBase *lb = template_ui->idlb;
const int flag = RNA_property_flag(template_ui->prop);
+ StringSearch *search = BLI_string_search_new();
+
/* ID listbase */
LISTBASE_FOREACH (ID *, id, lb) {
- if (!id_search_add(C, template_ui, flag, str, items, id)) {
+ if (id_search_allows_id(template_ui, flag, id, str)) {
+ BLI_string_search_add(search, id->name + 2, id);
+ }
+ }
+
+ ID **filtered_ids;
+ int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_ids);
+
+ for (int i = 0; i < filtered_amount; i++) {
+ if (!id_search_add(C, template_ui, items, filtered_ids[i])) {
break;
}
}
+
+ MEM_freeN(filtered_ids);
+ BLI_string_search_free(search);
}
/**
@@ -424,15 +433,29 @@ static void id_search_cb_tagged(const bContext *C,
ListBase *lb = template_ui->idlb;
const int flag = RNA_property_flag(template_ui->prop);
+ StringSearch *search = BLI_string_search_new();
+
/* ID listbase */
LISTBASE_FOREACH (ID *, id, lb) {
if (id->tag & LIB_TAG_DOIT) {
- if (!id_search_add(C, template_ui, flag, str, items, id)) {
- break;
+ if (id_search_allows_id(template_ui, flag, id, str)) {
+ BLI_string_search_add(search, id->name + 2, id);
}
id->tag &= ~LIB_TAG_DOIT;
}
}
+
+ ID **filtered_ids;
+ int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_ids);
+
+ for (int i = 0; i < filtered_amount; i++) {
+ if (!id_search_add(C, template_ui, items, filtered_ids[i])) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_ids);
+ BLI_string_search_free(search);
}
/**
@@ -1949,27 +1972,6 @@ static bool constraint_panel_is_bone(Panel *panel)
}
/**
- * Get the constraints for the active pose bone or the active / pinned object.
- */
-static ListBase *get_constraints(const bContext *C, bool use_bone_constraints)
-{
- ListBase *constraints = {NULL};
- if (use_bone_constraints) {
- bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data;
- if (pose_bone != NULL) {
- constraints = &pose_bone->constraints;
- }
- }
- else {
- Object *ob = ED_object_active_context(C);
- if (ob != NULL) {
- constraints = &ob->constraints;
- }
- }
- return constraints;
-}
-
-/**
* Move a constraint to the index it's moved to after a drag and drop.
*/
static void constraint_reorder(bContext *C, Panel *panel, int new_index)
@@ -2043,7 +2045,13 @@ void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_
ARegion *region = CTX_wm_region(C);
Object *ob = ED_object_active_context(C);
- ListBase *constraints = get_constraints(C, use_bone_constraints);
+ ListBase *constraints = {NULL};
+ if (use_bone_constraints) {
+ constraints = ED_object_pose_constraint_list(C);
+ }
+ else {
+ constraints = ED_object_constraint_active_list(ob);
+ }
/* Switch between the bone panel ID function and the object panel ID function. */
uiListPanelIDFromDataFunc panel_id_func = use_bone_constraints ? bone_constraint_panel_id :
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 22171d8be66..0c4064b5693 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -133,6 +133,7 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
.export_hair = RNA_boolean_get(op->ptr, "export_hair"),
.export_particles = RNA_boolean_get(op->ptr, "export_particles"),
+ .use_instancing = RNA_boolean_get(op->ptr, "use_instancing"),
.packuv = RNA_boolean_get(op->ptr, "packuv"),
.triangulate = RNA_boolean_get(op->ptr, "triangulate"),
.quad_method = RNA_enum_get(op->ptr, "quad_method"),
@@ -189,6 +190,7 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemS(col);
uiItemR(col, imfptr, "flatten", 0, NULL, ICON_NONE);
+ uiItemR(sub, imfptr, "use_instancing", 0, IFACE_("Use Instancing"), ICON_NONE);
sub = uiLayoutColumnWithHeading(col, true, IFACE_("Only"));
uiItemR(sub, imfptr, "selected", 0, IFACE_("Selected Objects"), ICON_NONE);
uiItemR(sub, imfptr, "renderable_only", 0, IFACE_("Renderable Objects"), ICON_NONE);
@@ -401,6 +403,13 @@ void WM_OT_alembic_export(wmOperatorType *ot)
"Curves as Mesh",
"Export curves and NURBS surfaces as meshes");
+ RNA_def_boolean(ot->srna,
+ "use_instancing",
+ true,
+ "Use Instancing",
+ "Export data of duplicated objects as Alembic instances; speeds up the export "
+ "and can be disabled for compatibility with other software");
+
RNA_def_float(
ot->srna,
"global_scale",
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index af99df4c5d8..1792f0e13bc 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -55,7 +55,7 @@
/* Loops over the mask-frames for a mask-layer, and applies the given callback */
bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
Scene *scene,
- short (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
+ bool (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
{
MaskLayerShape *mask_layer_shape;
@@ -310,38 +310,38 @@ void ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
/* -------------------------------------- */
/* Snap Tools */
-static short snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene *UNUSED(scene))
+static bool snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene *UNUSED(scene))
{
if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
mask_layer_shape->frame = (int)(floor(mask_layer_shape->frame + 0.5));
}
- return 0;
+ return false;
}
-static short snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
+static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
{
float secf = (float)FPS;
if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
mask_layer_shape->frame = (int)(floorf(mask_layer_shape->frame / secf + 0.5f) * secf);
}
- return 0;
+ return false;
}
-static short snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
+static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
{
if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
mask_layer_shape->frame = (int)CFRA;
}
- return 0;
+ return false;
}
-static short snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
+static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
{
if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
mask_layer_shape->frame = (int)ED_markers_find_nearest_marker_time(
&scene->markers, (float)mask_layer_shape->frame);
}
- return 0;
+ return false;
}
/* snap selected frames to ... */
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index dd4b8146154..a90d6530453 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -158,13 +158,13 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op)
}
else {
double offset_val = (double)RNA_float_get(op->ptr, "offset");
- bUnit_AsString2(offset_str,
- NUM_STR_REP_LEN,
- offset_val * sce->unit.scale_length,
- 3,
- B_UNIT_LENGTH,
- &sce->unit,
- true);
+ BKE_unit_value_as_string(offset_str,
+ NUM_STR_REP_LEN,
+ offset_val * sce->unit.scale_length,
+ 3,
+ B_UNIT_LENGTH,
+ &sce->unit,
+ true);
}
prop = RNA_struct_find_property(op->ptr, "offset_type");
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index bd14919d1d7..471d4847af6 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -891,7 +891,8 @@ void ED_mesh_mirror_topo_table_end(Object *UNUSED(ob))
ED_mesh_mirrtopo_free(&mesh_topo_store);
}
-static int ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
+/* Returns true on success. */
+static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
{
Mesh *me_mirror;
BMEditMesh *em_mirror;
@@ -900,7 +901,7 @@ static int ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
if (ED_mesh_mirrtopo_recalc_check(em_mirror, me_mirror, &mesh_topo_store)) {
ED_mesh_mirror_topo_table_begin(ob, me_eval);
}
- return 0;
+ return true;
}
/** \} */
@@ -921,7 +922,7 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
{
- if (ed_mesh_mirror_topo_table_update(ob, mesh) == -1) {
+ if (!ed_mesh_mirror_topo_table_update(ob, mesh)) {
return -1;
}
@@ -963,7 +964,7 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob,
int index)
{
intptr_t poinval;
- if (ed_mesh_mirror_topo_table_update(ob, NULL) == -1) {
+ if (!ed_mesh_mirror_topo_table_update(ob, NULL)) {
return NULL;
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index bfb13fb99bf..482ae4019c3 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -2572,7 +2572,9 @@ static int object_convert_exec(bContext *C, wmOperator *op)
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
- ED_rigidbody_object_remove(bmain, scene, newob);
+ if (newob->rigidbody_object != NULL) {
+ ED_rigidbody_object_remove(bmain, scene, newob);
+ }
}
}
else if (ob->type == OB_MESH && target == OB_GPENCIL) {
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 2cca3045aee..2f9917a2674 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -80,8 +80,9 @@
/** \name Constraint Data Accessors
* \{ */
-/* if object in posemode, active bone constraints, else object constraints */
-ListBase *ED_object_constraint_list_from_context(Object *ob)
+/* If object is in posemode, return active bone constraints, else object constraints. No
+ * constraints are returned for a bone on an inactive bonelayer. */
+ListBase *ED_object_constraint_active_list(Object *ob)
{
if (ob == NULL) {
return NULL;
@@ -102,6 +103,18 @@ ListBase *ED_object_constraint_list_from_context(Object *ob)
return NULL;
}
+/* Get the constraints for the active pose bone. Bone may be on an inactive bonelayer (unlike
+ * ED_object_constraint_active_list, such constraints are not excluded here). */
+ListBase *ED_object_pose_constraint_list(const bContext *C)
+{
+ bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data;
+ if (pose_bone == NULL) {
+ return NULL;
+ }
+
+ return &pose_bone->constraints;
+}
+
/* Find the list that a given constraint belongs to,
* and/or also get the posechannel this is from (if applicable) */
ListBase *ED_object_constraint_list_from_constraint(Object *ob,
@@ -147,7 +160,7 @@ ListBase *ED_object_constraint_list_from_constraint(Object *ob,
/* single constraint */
bConstraint *ED_object_constraint_active_get(Object *ob)
{
- return BKE_constraints_active_get(ED_object_constraint_list_from_context(ob));
+ return BKE_constraints_active_get(ED_object_constraint_active_list(ob));
}
/** \} */
@@ -780,7 +793,7 @@ static bool edit_constraint_invoke_properties(bContext *C,
return false;
}
-static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int type)
+static bConstraint *edit_constraint_property_get(bContext *C, wmOperator *op, Object *ob, int type)
{
char constraint_name[MAX_NAME];
int owner = RNA_enum_get(op->ptr, "owner");
@@ -789,31 +802,11 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int
RNA_string_get(op->ptr, "constraint", constraint_name);
- if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) {
- list = &ob->constraints;
- }
- else if (owner == EDIT_CONSTRAINT_OWNER_BONE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
- if (pchan) {
- list = &pchan->constraints;
- }
- else {
-#if 0
- if (G.debug & G_DEBUG) {
- printf("edit_constraint_property_get: No active bone for object '%s'\n",
- (ob) ? ob->id.name + 2 : "<None>");
- }
-#endif
- return NULL;
- }
+ if (owner == EDIT_CONSTRAINT_OWNER_BONE) {
+ list = ED_object_pose_constraint_list(C);
}
else {
-#if 0
- if (G.debug & G_DEBUG) {
- printf("edit_constraint_property_get: defaulting to getting list in the standard way\n");
- }
-#endif
- list = ED_object_constraint_list_from_context(ob);
+ list = ED_object_constraint_active_list(ob);
}
con = BKE_constraints_find_name(list, constraint_name);
@@ -842,7 +835,7 @@ static int stretchto_reset_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_STRETCHTO);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_STRETCHTO);
bStretchToConstraint *data = (con) ? (bStretchToConstraint *)con->data : NULL;
/* despite 3 layers of checks, we may still not be able to find a constraint */
@@ -897,7 +890,7 @@ static int limitdistance_reset_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_DISTLIMIT);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_DISTLIMIT);
bDistLimitConstraint *data = (con) ? (bDistLimitConstraint *)con->data : NULL;
/* despite 3 layers of checks, we may still not be able to find a constraint */
@@ -969,7 +962,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_CHILDOF);
bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL;
/* despite 3 layers of checks, we may still not be able to find a constraint */
@@ -1023,7 +1016,7 @@ static int childof_clear_inverse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_CHILDOF);
bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL;
if (data == NULL) {
@@ -1077,7 +1070,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_FOLLOWPATH);
bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL;
bAction *act = NULL;
@@ -1221,7 +1214,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL;
/* despite 3 layers of checks, we may still not be able to find a constraint */
@@ -1283,7 +1276,7 @@ static int objectsolver_clear_inverse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL;
if (data == NULL) {
@@ -1431,7 +1424,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, 0);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, 0);
ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL);
/* Store name temporarily for report. */
@@ -1497,7 +1490,7 @@ void CONSTRAINT_OT_delete(wmOperatorType *ot)
static int constraint_move_down_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, 0);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, 0);
if (con && con->next) {
ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
@@ -1552,7 +1545,7 @@ void CONSTRAINT_OT_move_down(wmOperatorType *ot)
static int constraint_move_up_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, 0);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, 0);
if (con && con->prev) {
ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
@@ -1605,7 +1598,7 @@ void CONSTRAINT_OT_move_up(wmOperatorType *ot)
static int constraint_move_to_index_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
- bConstraint *con = edit_constraint_property_get(op, ob, 0);
+ bConstraint *con = edit_constraint_property_get(C, op, ob, 0);
int new_index = RNA_int_get(op->ptr, "index");
if (new_index < 0) {
@@ -2161,8 +2154,7 @@ static int pose_constraint_add_exec(bContext *C, wmOperator *op)
with_targets = 1;
}
- return constraint_add_exec(
- C, op, ob, ED_object_constraint_list_from_context(ob), type, with_targets);
+ return constraint_add_exec(C, op, ob, ED_object_constraint_active_list(ob), type, with_targets);
}
/* ------------------ */
@@ -2363,12 +2355,8 @@ static int pose_ik_add_exec(bContext *C, wmOperator *op)
/* add the constraint - all necessary checks should have
* been done by the invoke() callback already... */
- return constraint_add_exec(C,
- op,
- ob,
- ED_object_constraint_list_from_context(ob),
- CONSTRAINT_TYPE_KINEMATIC,
- with_targets);
+ return constraint_add_exec(
+ C, op, ob, ED_object_constraint_active_list(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets);
}
void POSE_OT_ik_add(wmOperatorType *ot)
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 8bec200cb40..da00a88ab65 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -85,7 +85,7 @@ static const EnumPropertyItem DT_layer_items[] = {
"Transfer Freestyle edge mark"},
{0, "", 0, "Face Corner Data", ""},
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
- {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"},
+ {DT_TYPE_VCOL, "VCOL", 0, "Vertex Colors", "Vertex (face corners) colors"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
{0, "", 0, "Face Data", ""},
{DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"},
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d9196425098..4adf1a8d9f2 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -678,8 +678,8 @@ EnumPropertyItem prop_make_parent_types[] = {
bool ED_object_parent_set(ReportList *reports,
const bContext *C,
Scene *scene,
- Object *ob,
- Object *par,
+ Object *const ob,
+ Object *const par,
int partype,
const bool xmirror,
const bool keep_transform,
@@ -689,99 +689,111 @@ bool ED_object_parent_set(ReportList *reports,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
bPoseChannel *pchan = NULL;
bPoseChannel *pchan_eval = NULL;
- const bool pararm = ELEM(
- partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
Object *parent_eval = DEG_get_evaluated_object(depsgraph, par);
DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- /* preconditions */
- if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) {
- if (par->type != OB_CURVE) {
- return 0;
- }
- Curve *cu = par->data;
- Curve *cu_eval = parent_eval->data;
- if ((cu->flag & CU_PATH) == 0) {
- cu->flag |= CU_PATH | CU_FOLLOW;
- cu_eval->flag |= CU_PATH | CU_FOLLOW;
- /* force creation of path data */
- BKE_displist_make_curveTypes(depsgraph, scene, par, false, false);
- }
- else {
- cu->flag |= CU_FOLLOW;
- cu_eval->flag |= CU_FOLLOW;
- }
+ /* Preconditions. */
+ if (ob == par) {
+ /* Parenting an object to itself is impossible. */
+ return true;
+ }
- /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */
- if (partype == PAR_FOLLOW) {
- /* get or create F-Curve */
- bAction *act = ED_id_action_ensure(bmain, &cu->id);
- FCurve *fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0);
+ if (BKE_object_parent_loop_check(par, ob)) {
+ BKE_report(reports, RPT_ERROR, "Loop in parents");
+ return false;
+ }
- /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
- if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) {
- add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu);
+ switch (partype) {
+ case PAR_FOLLOW:
+ case PAR_PATH_CONST: {
+ if (par->type != OB_CURVE) {
+ return false;
+ }
+ Curve *cu = par->data;
+ Curve *cu_eval = parent_eval->data;
+ if ((cu->flag & CU_PATH) == 0) {
+ cu->flag |= CU_PATH | CU_FOLLOW;
+ cu_eval->flag |= CU_PATH | CU_FOLLOW;
+ /* force creation of path data */
+ BKE_displist_make_curveTypes(depsgraph, scene, par, false, false);
+ }
+ else {
+ cu->flag |= CU_FOLLOW;
+ cu_eval->flag |= CU_FOLLOW;
}
- }
- /* fall back on regular parenting now (for follow only) */
- if (partype == PAR_FOLLOW) {
- partype = PAR_OBJECT;
- }
- }
- else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) {
- pchan = BKE_pose_channel_active(par);
- pchan_eval = BKE_pose_channel_active(parent_eval);
+ /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */
+ if (partype == PAR_FOLLOW) {
+ /* get or create F-Curve */
+ bAction *act = ED_id_action_ensure(bmain, &cu->id);
+ FCurve *fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0);
- if (pchan == NULL) {
- BKE_report(reports, RPT_ERROR, "No active bone");
- return false;
- }
- }
+ /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
+ if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) {
+ add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu);
+ }
+ }
- if (ob != par) {
- if (BKE_object_parent_loop_check(par, ob)) {
- BKE_report(reports, RPT_ERROR, "Loop in parents");
- return false;
+ /* fall back on regular parenting now (for follow only) */
+ if (partype == PAR_FOLLOW) {
+ partype = PAR_OBJECT;
+ }
+ break;
}
+ case PAR_BONE:
+ case PAR_BONE_RELATIVE:
+ pchan = BKE_pose_channel_active(par);
+ pchan_eval = BKE_pose_channel_active(parent_eval);
- Object workob;
+ if (pchan == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active bone");
+ return false;
+ }
+ }
- /* apply transformation of previous parenting */
- if (keep_transform) {
- /* was removed because of bug [#23577],
- * but this can be handy in some cases too [#32616], so make optional */
- BKE_object_apply_mat4(ob, ob->obmat, false, false);
- }
+ Object workob;
- /* set the parent (except for follow-path constraint option) */
- if (partype != PAR_PATH_CONST) {
- ob->parent = par;
- /* Always clear parentinv matrix for sake of consistency, see T41950. */
- unit_m4(ob->parentinv);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- }
+ /* Apply transformation of previous parenting. */
+ if (keep_transform) {
+ /* was removed because of bug [#23577],
+ * but this can be handy in some cases too [#32616], so make optional */
+ BKE_object_apply_mat4(ob, ob->obmat, false, false);
+ }
- /* handle types */
- if (pchan) {
- BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr));
- }
- else {
- ob->parsubstr[0] = 0;
- }
+ /* Set the parent (except for follow-path constraint option). */
+ if (partype != PAR_PATH_CONST) {
+ ob->parent = par;
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
- if (partype == PAR_PATH_CONST) {
- /* don't do anything here, since this is not technically "parenting" */
- }
- else if (ELEM(partype, PAR_CURVE, PAR_LATTICE) || (pararm)) {
+ /* Handle types. */
+ if (pchan) {
+ BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr));
+ }
+ else {
+ ob->parsubstr[0] = 0;
+ }
+
+ switch (partype) {
+ case PAR_PATH_CONST:
+ /* Don't do anything here, since this is not technically "parenting". */
+ break;
+ case PAR_CURVE:
+ case PAR_LATTICE:
+ case PAR_ARMATURE:
+ case PAR_ARMATURE_NAME:
+ case PAR_ARMATURE_ENVELOPE:
+ case PAR_ARMATURE_AUTO:
/* partype is now set to PAROBJECT so that invisible 'virtual'
* modifiers don't need to be created.
* NOTE: the old (2.4x) method was to set ob->partype = PARSKEL,
* creating the virtual modifiers.
*/
- ob->partype = PAROBJECT; /* note, dna define, not operator property */
- /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */
+ ob->partype = PAROBJECT; /* Note: DNA define, not operator property. */
+ /* ob->partype = PARSKEL; */ /* Note: DNA define, not operator property. */
/* BUT, to keep the deforms, we need a modifier,
* and then we need to set the object that it uses
@@ -823,109 +835,111 @@ bool ED_object_parent_set(ReportList *reports,
break;
}
}
- }
- else if (partype == PAR_BONE) {
- ob->partype = PARBONE; /* note, dna define, not operator property */
+ break;
+ case PAR_BONE:
+ ob->partype = PARBONE; /* Note: DNA define, not operator property. */
if (pchan->bone) {
pchan->bone->flag &= ~BONE_RELATIVE_PARENTING;
pchan_eval->bone->flag &= ~BONE_RELATIVE_PARENTING;
}
- }
- else if (partype == PAR_BONE_RELATIVE) {
- ob->partype = PARBONE; /* note, dna define, not operator property */
+ break;
+ case PAR_BONE_RELATIVE:
+ ob->partype = PARBONE; /* Note: DNA define, not operator property. */
if (pchan->bone) {
pchan->bone->flag |= BONE_RELATIVE_PARENTING;
pchan_eval->bone->flag |= BONE_RELATIVE_PARENTING;
}
- }
- else if (partype == PAR_VERTEX) {
+ break;
+ case PAR_VERTEX:
ob->partype = PARVERT1;
ob->par1 = vert_par[0];
- }
- else if (partype == PAR_VERTEX_TRI) {
+ break;
+ case PAR_VERTEX_TRI:
ob->partype = PARVERT3;
copy_v3_v3_int(&ob->par1, vert_par);
- }
- else {
- ob->partype = PAROBJECT; /* note, dna define, not operator property */
- }
+ break;
+ case PAR_OBJECT:
+ case PAR_FOLLOW:
+ ob->partype = PAROBJECT; /* Note: DNA define, not operator property. */
+ break;
+ }
- /* constraint */
- if (partype == PAR_PATH_CONST) {
- bConstraint *con;
- bFollowPathConstraint *data;
- float cmat[4][4], vec[3];
+ /* Constraint and set parent inverse. */
+ const bool is_armature_parent = ELEM(
+ partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
+ if (partype == PAR_PATH_CONST) {
+ bConstraint *con;
+ bFollowPathConstraint *data;
+ float cmat[4][4], vec[3];
- con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
+ con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
- data = con->data;
- data->tar = par;
+ data = con->data;
+ data->tar = par;
- BKE_constraint_target_matrix_get(
- depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
- sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
+ BKE_constraint_target_matrix_get(
+ depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
+ sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
- copy_v3_v3(ob->loc, vec);
+ copy_v3_v3(ob->loc, vec);
+ }
+ else if (is_armature_parent && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) {
+ if (partype == PAR_ARMATURE_NAME) {
+ ED_object_vgroup_calc_from_armature(
+ reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false);
}
- else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) {
- if (partype == PAR_ARMATURE_NAME) {
- ED_object_vgroup_calc_from_armature(
- reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false);
- }
- else if (partype == PAR_ARMATURE_ENVELOPE) {
- ED_object_vgroup_calc_from_armature(
- reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror);
- }
- else if (partype == PAR_ARMATURE_AUTO) {
- WM_cursor_wait(1);
- ED_object_vgroup_calc_from_armature(
- reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror);
- WM_cursor_wait(0);
- }
- /* get corrected inverse */
- ob->partype = PAROBJECT;
- BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
-
- invert_m4_m4(ob->parentinv, workob.obmat);
+ else if (partype == PAR_ARMATURE_ENVELOPE) {
+ ED_object_vgroup_calc_from_armature(
+ reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror);
}
- else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) {
- if (partype == PAR_ARMATURE) {
- ED_gpencil_add_armature(C, reports, ob, par);
- }
- else if (partype == PAR_ARMATURE_NAME) {
- ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME);
- }
- else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) {
- WM_cursor_wait(1);
- ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO);
- WM_cursor_wait(0);
- }
- /* get corrected inverse */
- ob->partype = PAROBJECT;
- BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
-
- invert_m4_m4(ob->parentinv, workob.obmat);
+ else if (partype == PAR_ARMATURE_AUTO) {
+ WM_cursor_wait(1);
+ ED_object_vgroup_calc_from_armature(
+ reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror);
+ WM_cursor_wait(0);
}
- else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) {
- /* Add Lattice modifier */
- if (partype == PAR_LATTICE) {
- ED_gpencil_add_lattice_modifier(C, reports, ob, par);
- }
- /* get corrected inverse */
- ob->partype = PAROBJECT;
- BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
+ /* get corrected inverse */
+ ob->partype = PAROBJECT;
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
- invert_m4_m4(ob->parentinv, workob.obmat);
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ else if (is_armature_parent && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) {
+ if (partype == PAR_ARMATURE) {
+ ED_gpencil_add_armature(C, reports, ob, par);
}
- else {
- /* calculate inverse parent matrix */
- BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
- invert_m4_m4(ob->parentinv, workob.obmat);
+ else if (partype == PAR_ARMATURE_NAME) {
+ ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME);
+ }
+ else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) {
+ WM_cursor_wait(1);
+ ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO);
+ WM_cursor_wait(0);
}
+ /* get corrected inverse */
+ ob->partype = PAROBJECT;
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) {
+ /* Add Lattice modifier */
+ if (partype == PAR_LATTICE) {
+ ED_gpencil_add_lattice_modifier(C, reports, ob, par);
+ }
+ /* get corrected inverse */
+ ob->partype = PAROBJECT;
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
+
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ else {
+ /* calculate inverse parent matrix */
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
+ invert_m4_m4(ob->parentinv, workob.obmat);
}
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
return true;
}
@@ -954,58 +968,104 @@ static void parent_set_vert_find(KDTree_3d *tree, Object *child, int vert_par[3]
}
}
-static int parent_set_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *par = ED_object_active_context(C);
- int partype = RNA_enum_get(op->ptr, "type");
- const bool xmirror = RNA_boolean_get(op->ptr, "xmirror");
- const bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
- bool ok = true;
-
- /* vertex parent (kdtree) */
- const bool is_vert_par = ELEM(partype, PAR_VERTEX, PAR_VERTEX_TRI);
- const bool is_tri = partype == PAR_VERTEX_TRI;
- int tree_tot;
- struct KDTree_3d *tree = NULL;
- int vert_par[3] = {0, 0, 0};
- const int *vert_par_p = is_vert_par ? vert_par : NULL;
-
- if (is_vert_par) {
- tree = BKE_object_as_kdtree(par, &tree_tot);
- BLI_assert(tree != NULL);
+struct ParentingContext {
+ ReportList *reports;
+ Scene *scene;
+ Object *par;
+ int partype;
+ bool is_vertex_tri;
+ bool xmirror;
+ bool keep_transform;
+};
- if (tree_tot < (is_tri ? 3 : 1)) {
- BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent");
- ok = false;
+static bool parent_set_nonvertex_parent(bContext *C, struct ParentingContext *parenting_context)
+{
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ if (!ED_object_parent_set(parenting_context->reports,
+ C,
+ parenting_context->scene,
+ ob,
+ parenting_context->par,
+ parenting_context->partype,
+ parenting_context->xmirror,
+ parenting_context->keep_transform,
+ NULL)) {
+ return false;
}
}
+ CTX_DATA_END;
- if (ok) {
- /* Non vertex-parent */
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- if (is_vert_par) {
- parent_set_vert_find(tree, ob, vert_par, is_tri);
- }
+ return true;
+}
- if (!ED_object_parent_set(
- op->reports, C, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
- ok = false;
- break;
- }
+static bool parent_set_vertex_parent_with_kdtree(bContext *C,
+ struct ParentingContext *parenting_context,
+ struct KDTree_3d *tree)
+{
+ int vert_par[3] = {0, 0, 0};
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ parent_set_vert_find(tree, ob, vert_par, parenting_context->is_vertex_tri);
+ if (!ED_object_parent_set(parenting_context->reports,
+ C,
+ parenting_context->scene,
+ ob,
+ parenting_context->par,
+ parenting_context->partype,
+ parenting_context->xmirror,
+ parenting_context->keep_transform,
+ vert_par)) {
+ return false;
}
- CTX_DATA_END;
}
+ CTX_DATA_END;
+ return true;
+}
+
+static bool parent_set_vertex_parent(bContext *C, struct ParentingContext *parenting_context)
+{
+ struct KDTree_3d *tree = NULL;
+ int tree_tot;
+
+ tree = BKE_object_as_kdtree(parenting_context->par, &tree_tot);
+ BLI_assert(tree != NULL);
- if (is_vert_par) {
+ if (tree_tot < (parenting_context->is_vertex_tri ? 3 : 1)) {
+ BKE_report(parenting_context->reports, RPT_ERROR, "Not enough vertices for vertex-parent");
BLI_kdtree_3d_free(tree);
+ return false;
}
+ const bool ok = parent_set_vertex_parent_with_kdtree(C, parenting_context, tree);
+ BLI_kdtree_3d_free(tree);
+ return ok;
+}
+
+static int parent_set_exec(bContext *C, wmOperator *op)
+{
+ const int partype = RNA_enum_get(op->ptr, "type");
+ struct ParentingContext parenting_context = {
+ .reports = op->reports,
+ .scene = CTX_data_scene(C),
+ .par = ED_object_active_context(C),
+ .partype = partype,
+ .is_vertex_tri = partype == PAR_VERTEX_TRI,
+ .xmirror = RNA_boolean_get(op->ptr, "xmirror"),
+ .keep_transform = RNA_boolean_get(op->ptr, "keep_transform"),
+ };
+
+ bool ok;
+ if (ELEM(parenting_context.partype, PAR_VERTEX, PAR_VERTEX_TRI)) {
+ ok = parent_set_vertex_parent(C, &parenting_context);
+ }
+ else {
+ ok = parent_set_nonvertex_parent(C, &parenting_context);
+ }
if (!ok) {
return OPERATOR_CANCELLED;
}
+ Main *bmain = CTX_data_main(C);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index e20de5a92ff..5dfbaf583f6 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -440,7 +440,7 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op)
void OBJECT_OT_select_by_type(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select By Type";
+ ot->name = "Select by Type";
ot->description = "Select all visible objects that are of a type";
ot->idname = "OBJECT_OT_select_by_type";
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 6c3b47db155..32b91dbd327 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -89,7 +89,7 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "screen_intern.h" /* own module include */
@@ -105,55 +105,55 @@
bool ED_operator_regionactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
- return 0;
+ return false;
}
if (CTX_wm_screen(C) == NULL) {
- return 0;
+ return false;
}
if (CTX_wm_region(C) == NULL) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
bool ED_operator_areaactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
- return 0;
+ return false;
}
if (CTX_wm_screen(C) == NULL) {
- return 0;
+ return false;
}
if (CTX_wm_area(C) == NULL) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
bool ED_operator_screenactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
- return 0;
+ return false;
}
if (CTX_wm_screen(C) == NULL) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* XXX added this to prevent anim state to change during renders */
static bool ED_operator_screenactive_norender(bContext *C)
{
if (G.is_rendering) {
- return 0;
+ return false;
}
if (CTX_wm_window(C) == NULL) {
- return 0;
+ return false;
}
if (CTX_wm_screen(C) == NULL) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* when mouse is over area-edge */
@@ -161,25 +161,25 @@ bool ED_operator_screen_mainwinactive(bContext *C)
{
bScreen *screen;
if (CTX_wm_window(C) == NULL) {
- return 0;
+ return false;
}
screen = CTX_wm_screen(C);
if (screen == NULL) {
- return 0;
+ return false;
}
if (screen->active_region != NULL) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
bool ED_operator_scene(bContext *C)
{
Scene *scene = CTX_data_scene(C);
if (scene) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
bool ED_operator_scene_editable(bContext *C)
@@ -197,18 +197,18 @@ bool ED_operator_objectmode(bContext *C)
Object *obact = CTX_data_active_object(C);
if (scene == NULL || ID_IS_LINKED(scene)) {
- return 0;
+ return false;
}
if (CTX_data_edit_object(C)) {
- return 0;
+ return false;
}
/* add a check for ob->mode too? */
if (obact && (obact->mode != OB_MODE_OBJECT)) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static bool ed_spacetype_test(bContext *C, int type)
@@ -217,7 +217,7 @@ static bool ed_spacetype_test(bContext *C, int type)
SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C);
return sl && (sl->spacetype == type);
}
- return 0;
+ return false;
}
bool ED_operator_view3d_active(bContext *C)
@@ -246,7 +246,7 @@ bool ED_operator_animview_active(bContext *C)
}
CTX_wm_operator_poll_msg_set(C, "expected a timeline/animation area to be active");
- return 0;
+ return false;
}
bool ED_operator_outliner_active(bContext *C)
@@ -260,11 +260,11 @@ bool ED_operator_outliner_active_no_editobject(bContext *C)
Object *ob = ED_object_active_context(C);
Object *obedit = CTX_data_edit_object(C);
if (ob && ob == obedit) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
bool ED_operator_file_active(bContext *C)
@@ -287,10 +287,10 @@ bool ED_operator_node_active(bContext *C)
SpaceNode *snode = CTX_wm_space_node(C);
if (snode && snode->edittree) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
bool ED_operator_node_editable(bContext *C)
@@ -298,10 +298,10 @@ bool ED_operator_node_editable(bContext *C)
SpaceNode *snode = CTX_wm_space_node(C);
if (snode && snode->edittree && !ID_IS_LINKED(snode->edittree)) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
bool ED_operator_graphedit_active(bContext *C)
@@ -400,7 +400,7 @@ bool ED_operator_editmesh(bContext *C)
if (obedit && obedit->type == OB_MESH) {
return NULL != BKE_editmesh_from_object(obedit);
}
- return 0;
+ return false;
}
bool ED_operator_editmesh_view3d(bContext *C)
@@ -411,11 +411,11 @@ bool ED_operator_editmesh_view3d(bContext *C)
bool ED_operator_editmesh_region_view3d(bContext *C)
{
if (ED_operator_editmesh(C) && CTX_wm_region_view3d(C)) {
- return 1;
+ return true;
}
CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editmesh");
- return 0;
+ return false;
}
bool ED_operator_editmesh_auto_smooth(bContext *C)
@@ -424,7 +424,7 @@ bool ED_operator_editmesh_auto_smooth(bContext *C)
if (obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)) {
return NULL != BKE_editmesh_from_object(obedit);
}
- return 0;
+ return false;
}
bool ED_operator_editarmature(bContext *C)
@@ -433,7 +433,7 @@ bool ED_operator_editarmature(bContext *C)
if (obedit && obedit->type == OB_ARMATURE) {
return NULL != ((bArmature *)obedit->data)->edbo;
}
- return 0;
+ return false;
}
/**
@@ -451,12 +451,12 @@ bool ED_operator_posemode_exclusive(bContext *C)
Object *obpose;
if ((obpose = BKE_object_pose_armature_get(obact))) {
if (obact == obpose) {
- return 1;
+ return true;
}
}
}
- return 0;
+ return false;
}
/* allows for pinned pose objects to be used in the object buttons
@@ -467,11 +467,11 @@ bool ED_operator_posemode_context(bContext *C)
if (obpose && !(obpose->mode & OB_MODE_EDIT)) {
if (BKE_object_pose_context_check(obpose)) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
bool ED_operator_posemode(bContext *C)
@@ -482,12 +482,12 @@ bool ED_operator_posemode(bContext *C)
Object *obpose;
if ((obpose = BKE_object_pose_armature_get(obact))) {
if ((obact == obpose) || (obact->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
- return 1;
+ return true;
}
}
}
- return 0;
+ return false;
}
bool ED_operator_posemode_local(bContext *C)
@@ -537,17 +537,17 @@ bool ED_operator_editsurfcurve(bContext *C)
if (obedit && ELEM(obedit->type, OB_CURVE, OB_SURF)) {
return NULL != ((Curve *)obedit->data)->editnurb;
}
- return 0;
+ return false;
}
bool ED_operator_editsurfcurve_region_view3d(bContext *C)
{
if (ED_operator_editsurfcurve(C) && CTX_wm_region_view3d(C)) {
- return 1;
+ return true;
}
CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editcurve");
- return 0;
+ return false;
}
bool ED_operator_editcurve(bContext *C)
@@ -556,7 +556,7 @@ bool ED_operator_editcurve(bContext *C)
if (obedit && obedit->type == OB_CURVE) {
return NULL != ((Curve *)obedit->data)->editnurb;
}
- return 0;
+ return false;
}
bool ED_operator_editcurve_3d(bContext *C)
@@ -567,7 +567,7 @@ bool ED_operator_editcurve_3d(bContext *C)
return (cu->flag & CU_3D) && (NULL != cu->editnurb);
}
- return 0;
+ return false;
}
bool ED_operator_editsurf(bContext *C)
@@ -576,7 +576,7 @@ bool ED_operator_editsurf(bContext *C)
if (obedit && obedit->type == OB_SURF) {
return NULL != ((Curve *)obedit->data)->editnurb;
}
- return 0;
+ return false;
}
bool ED_operator_editfont(bContext *C)
@@ -585,7 +585,7 @@ bool ED_operator_editfont(bContext *C)
if (obedit && obedit->type == OB_FONT) {
return NULL != ((Curve *)obedit->data)->editfont;
}
- return 0;
+ return false;
}
bool ED_operator_editlattice(bContext *C)
@@ -594,7 +594,7 @@ bool ED_operator_editlattice(bContext *C)
if (obedit && obedit->type == OB_LATTICE) {
return NULL != ((Lattice *)obedit->data)->editlatt;
}
- return 0;
+ return false;
}
bool ED_operator_editmball(bContext *C)
@@ -603,7 +603,7 @@ bool ED_operator_editmball(bContext *C)
if (obedit && obedit->type == OB_MBALL) {
return NULL != ((MetaBall *)obedit->data)->editelems;
}
- return 0;
+ return false;
}
bool ED_operator_mask(bContext *C)
@@ -649,11 +649,11 @@ static bool screen_active_editable(bContext *C)
if (ED_operator_screenactive(C)) {
/* no full window splitting allowed */
if (CTX_wm_screen(C)->state != SCREENNORMAL) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/** \} */
@@ -702,12 +702,12 @@ static bool actionzone_area_poll(bContext *C)
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
- return 1;
+ return true;
}
}
}
}
- return 0;
+ return false;
}
/* the debug drawing of the click_rect is in area_draw_azone_fullscreen, keep both in sync */
@@ -901,7 +901,7 @@ static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const b
ED_region_tag_redraw_no_rebuild(az->region);
}
else {
- BLI_assert(0);
+ BLI_assert(false);
}
}
}
@@ -1213,13 +1213,13 @@ typedef struct sAreaSwapData {
ScrArea *sa1, *sa2;
} sAreaSwapData;
-static int area_swap_init(wmOperator *op, const wmEvent *event)
+static bool area_swap_init(wmOperator *op, const wmEvent *event)
{
sAreaSwapData *sd = NULL;
sActionzoneData *sad = event->customdata;
if (sad == NULL || sad->sa1 == NULL) {
- return 0;
+ return false;
}
sd = MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
@@ -1227,7 +1227,7 @@ static int area_swap_init(wmOperator *op, const wmEvent *event)
sd->sa2 = sad->sa2;
op->customdata = sd;
- return 1;
+ return true;
}
static void area_swap_exit(bContext *C, wmOperator *op)
@@ -1246,7 +1246,6 @@ static void area_swap_cancel(bContext *C, wmOperator *op)
static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
-
if (!area_swap_init(op, event)) {
return OPERATOR_PASS_THROUGH;
}
@@ -1573,8 +1572,8 @@ static void area_move_set_limits(wmWindow *win,
}
/* validate selection inside screen, set variables OK */
-/* return 0: init failed */
-static int area_move_init(bContext *C, wmOperator *op)
+/* return false: init failed */
+static bool area_move_init(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
wmWindow *win = CTX_wm_window(C);
@@ -1589,7 +1588,7 @@ static int area_move_init(bContext *C, wmOperator *op)
/* setup */
actedge = screen_geom_find_active_scredge(win, screen, x, y);
if (actedge == NULL) {
- return 0;
+ return false;
}
md = MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
@@ -1615,7 +1614,7 @@ static int area_move_init(bContext *C, wmOperator *op)
md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
- return 1;
+ return true;
}
static int area_snap_calc_location(const bScreen *screen,
@@ -1985,7 +1984,7 @@ static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdat
}
/* generic init, menu case, doesn't need active area */
-static int area_split_menu_init(bContext *C, wmOperator *op)
+static bool area_split_menu_init(bContext *C, wmOperator *op)
{
sAreaSplitData *sd;
@@ -1995,11 +1994,11 @@ static int area_split_menu_init(bContext *C, wmOperator *op)
sd->sarea = CTX_wm_area(C);
- return 1;
+ return true;
}
/* generic init, no UI stuff here, assumes active area */
-static int area_split_init(bContext *C, wmOperator *op)
+static bool area_split_init(bContext *C, wmOperator *op)
{
ScrArea *area = CTX_wm_area(C);
sAreaSplitData *sd;
@@ -2008,7 +2007,7 @@ static int area_split_init(bContext *C, wmOperator *op)
/* required context */
if (area == NULL) {
- return 0;
+ return false;
}
/* required properties */
@@ -2016,10 +2015,10 @@ static int area_split_init(bContext *C, wmOperator *op)
/* minimal size */
if (dir == 'v' && area->winx < 2 * AREAMINX) {
- return 0;
+ return false;
}
if (dir == 'h' && area->winy < 2 * areaminy) {
- return 0;
+ return false;
}
/* custom data */
@@ -2036,7 +2035,7 @@ static int area_split_init(bContext *C, wmOperator *op)
sd->origsize = area->v2->vec.y - sd->origmin;
}
- return 1;
+ return true;
}
/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
@@ -2069,7 +2068,7 @@ static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *area, ScrArea *sb)
}
/* do the split, return success */
-static int area_split_apply(bContext *C, wmOperator *op)
+static bool area_split_apply(bContext *C, wmOperator *op)
{
const wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
@@ -2108,10 +2107,10 @@ static int area_split_apply(bContext *C, wmOperator *op)
/* Update preview thumbnail */
BKE_icon_changed(screen->id.icon_id);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static void area_split_exit(bContext *C, wmOperator *op)
@@ -3277,8 +3276,8 @@ static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata
}
/* validate selection inside screen, set variables OK */
-/* return 0: init failed */
-static int area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa2)
+/* return false: init failed */
+static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa2)
{
if (sa1 == NULL || sa2 == NULL) {
/* Get areas from cursor location if not specified. */
@@ -3287,7 +3286,7 @@ static int area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa
screen_area_edge_from_cursor(C, cursor, &sa1, &sa2);
}
if (sa1 == NULL || sa2 == NULL) {
- return 0;
+ return false;
}
sAreaJoinData *jd = MEM_callocN(sizeof(sAreaJoinData), "op_area_join");
@@ -3299,26 +3298,26 @@ static int area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa
jd->draw_callback = WM_draw_cb_activate(CTX_wm_window(C), area_join_draw_cb, op);
- return 1;
+ return true;
}
/* apply the join of the areas (space types) */
-static int area_join_apply(bContext *C, wmOperator *op)
+static bool area_join_apply(bContext *C, wmOperator *op)
{
sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
if (!jd) {
- return 0;
+ return false;
}
if (!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)) {
- return 0;
+ return false;
}
if (CTX_wm_area(C) == jd->sa2) {
CTX_wm_area_set(C, NULL);
CTX_wm_region_set(C, NULL);
}
- return 1;
+ return true;
}
/* finish operation */
@@ -4006,7 +4005,7 @@ static bool region_toggle_poll(bContext *C)
/* Don't flip anything around in top-bar. */
if (area && area->spacetype == SPACE_TOPBAR) {
CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed");
- return 0;
+ return false;
}
return ED_operator_areaactive(C);
@@ -5593,10 +5592,10 @@ static bool blend_file_drop_poll(bContext *UNUSED(C),
{
if (drag->type == WM_DRAG_PATH) {
if (drag->icon == ICON_FILE_BLEND) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static void blend_file_drop_copy(wmDrag *drag, wmDropBox *drop)
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 08733a26187..f4d7869e40a 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1154,7 +1154,8 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr,
if (ss->preview_vert_index_count > 0) {
immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
for (int i = 0; i < ss->preview_vert_index_count; i++) {
- immVertex3fv(gpuattr, SCULPT_vertex_co_get(ss, ss->preview_vert_index_list[i]));
+ immVertex3fv(gpuattr,
+ SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_index_list[i]));
}
immEnd();
}
@@ -1572,7 +1573,14 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
/* Cursor location symmetry points. */
- const float *active_vertex_co = SCULPT_active_vertex_co_get(pcontext->ss);
+ const float *active_vertex_co;
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
+ active_vertex_co = SCULPT_vertex_co_for_grab_active_get(
+ pcontext->ss, SCULPT_active_vertex_get(pcontext->ss));
+ }
+ else {
+ active_vertex_co = SCULPT_active_vertex_co_get(pcontext->ss);
+ }
if (len_v3v3(active_vertex_co, pcontext->location) < pcontext->radius) {
immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha);
cursor_draw_point_with_symmetry(pcontext->pos,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 456c1f61cb1..3886b78286b 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -90,7 +90,7 @@
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_init_exit.h"
#include "WM_api.h"
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fd17793b6de..70f8ef89e9a 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -23,14 +23,18 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_vec_types.h"
+#include "BLI_alloca.h"
#include "BLI_bitmap_draw_2d.h"
#include "BLI_lasso_2d.h"
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
+#include "BLI_polyfill_2d.h"
#include "BLI_rect.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -56,6 +60,8 @@
#include "ED_view3d.h"
#include "bmesh.h"
+#include "bmesh_tools.h"
+#include "tools/bmesh_boolean.h"
#include "paint_intern.h"
@@ -256,10 +262,18 @@ typedef struct SculptGestureContext {
struct SculptGestureOperation *operation;
+ /* Gesture data. */
+ /* Screen space points that represent the gesture shape. */
+ float (*gesture_points)[2];
+ int tot_gesture_points;
+
/* View parameters. */
float true_view_normal[3];
float view_normal[3];
+ float true_view_origin[3];
+ float view_origin[3];
+
float true_clip_planes[4][4];
float clip_planes[4][4];
@@ -319,6 +333,9 @@ static void sculpt_gesture_context_init_common(bContext *C,
copy_m3_m4(mat, ob->imat);
mul_m3_v3(mat, view_dir);
normalize_v3_v3(sgcontext->true_view_normal, view_dir);
+
+ /* View Origin. */
+ copy_v3_v3(sgcontext->true_view_origin, sgcontext->vc.rv3d->viewinv[3]);
}
static void sculpt_gesture_lasso_px_cb(int x, int x_end, int y, void *user_data)
@@ -370,6 +387,14 @@ static SculptGestureContext *sculpt_gesture_init_from_lasso(bContext *C, wmOpera
sgcontext->vc.region,
sgcontext->vc.obact,
&sgcontext->lasso.boundbox);
+
+ sgcontext->gesture_points = MEM_malloc_arrayN(mcoords_len, sizeof(float[2]), "trim points");
+ sgcontext->tot_gesture_points = mcoords_len;
+ for (int i = 0; i < mcoords_len; i++) {
+ sgcontext->gesture_points[i][0] = mcoords[i][0];
+ sgcontext->gesture_points[i][1] = mcoords[i][1];
+ }
+
MEM_freeN((void *)mcoords);
return sgcontext;
@@ -390,12 +415,27 @@ static SculptGestureContext *sculpt_gesture_init_from_box(bContext *C, wmOperato
ED_view3d_clipping_calc(
&bb, sgcontext->true_clip_planes, sgcontext->vc.region, sgcontext->vc.obact, &rect);
+ sgcontext->gesture_points = MEM_calloc_arrayN(4, sizeof(float[2]), "trim points");
+ sgcontext->tot_gesture_points = 4;
+
+ sgcontext->gesture_points[0][0] = rect.xmax;
+ sgcontext->gesture_points[0][1] = rect.ymax;
+
+ sgcontext->gesture_points[1][0] = rect.xmax;
+ sgcontext->gesture_points[1][1] = rect.ymin;
+
+ sgcontext->gesture_points[2][0] = rect.xmin;
+ sgcontext->gesture_points[2][1] = rect.ymin;
+
+ sgcontext->gesture_points[3][0] = rect.xmin;
+ sgcontext->gesture_points[3][1] = rect.ymax;
return sgcontext;
}
static void sculpt_gesture_context_free(SculptGestureContext *sgcontext)
{
MEM_SAFE_FREE(sgcontext->lasso.mask_px);
+ MEM_SAFE_FREE(sgcontext->gesture_points);
MEM_SAFE_FREE(sgcontext->operation);
MEM_SAFE_FREE(sgcontext->nodes);
MEM_SAFE_FREE(sgcontext);
@@ -434,6 +474,7 @@ static void sculpt_gesture_flip_for_symmetry_pass(SculptGestureContext *sgcontex
}
negate_m4(sgcontext->clip_planes);
flip_v3_v3(sgcontext->view_normal, sgcontext->true_view_normal, symmpass);
+ flip_v3_v3(sgcontext->view_origin, sgcontext->true_view_origin, symmpass);
}
static void sculpt_gesture_update_effected_nodes(SculptGestureContext *sgcontext)
@@ -699,6 +740,361 @@ static void paint_mask_gesture_operator_properties(wmOperatorType *ot)
1.0f);
}
+/* Trim Gesture Operation. */
+
+typedef enum eSculptTrimOperationType {
+ SCULPT_GESTURE_TRIM_INTERSECT,
+ SCULPT_GESTURE_TRIM_DIFFERENCE,
+} eSculptTrimOperationType;
+
+static EnumPropertyItem prop_trim_operation_types[] = {
+ {SCULPT_GESTURE_TRIM_INTERSECT, "INTERSECT", 0, "Intersect", ""},
+ {SCULPT_GESTURE_TRIM_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef struct SculptGestureTrimOperation {
+ SculptGestureOperation op;
+
+ Mesh *mesh;
+ float (*true_mesh_co)[3];
+
+ float depth_front;
+ float depth_back;
+
+ eSculptTrimOperationType mode;
+} SculptGestureTrimOperation;
+
+static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
+{
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+ Mesh *trim_mesh = trim_operation->mesh;
+ BKE_mesh_calc_normals(trim_mesh);
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(trim_mesh);
+ BMesh *bm;
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ trim_mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
+ BMO_op_callf(bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "recalc_face_normals faces=%hf",
+ BM_ELEM_TAG);
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }),
+ trim_mesh);
+ BM_mesh_free(bm);
+ BKE_mesh_free(trim_mesh);
+ trim_operation->mesh = result;
+}
+
+static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext)
+{
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+
+ SculptSession *ss = sgcontext->ss;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ float view_plane[4];
+ plane_from_point_normal_v3(view_plane, sgcontext->true_view_origin, sgcontext->true_view_normal);
+
+ trim_operation->depth_front = FLT_MAX;
+ trim_operation->depth_back = -FLT_MAX;
+
+ for (int i = 0; i < totvert; i++) {
+ const float *vco = SCULPT_vertex_co_get(ss, i);
+ const float dist = dist_signed_to_plane_v3(vco, view_plane);
+ trim_operation->depth_front = min_ff(dist, trim_operation->depth_front);
+ trim_operation->depth_back = max_ff(dist, trim_operation->depth_back);
+ }
+}
+
+static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontext)
+{
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+ ViewContext *vc = &sgcontext->vc;
+ ARegion *region = vc->region;
+
+ const int tot_screen_points = sgcontext->tot_gesture_points;
+ float(*screen_points)[2] = sgcontext->gesture_points;
+
+ const int trim_totverts = tot_screen_points * 2;
+ const int trim_totpolys = (2 * (tot_screen_points - 2)) + (2 * tot_screen_points);
+ trim_operation->mesh = BKE_mesh_new_nomain(
+ trim_totverts, 0, 0, trim_totpolys * 3, trim_totpolys);
+ trim_operation->true_mesh_co = MEM_malloc_arrayN(trim_totverts, 3 * sizeof(float), "mesh orco");
+
+ const float depth_front = trim_operation->depth_front - 0.1f;
+ const float depth_back = trim_operation->depth_back + 0.1f;
+
+ float *view_origin = sgcontext->true_view_origin;
+ float *view_normal = sgcontext->true_view_normal;
+
+ /* Write vertices coordinates for the front face. */
+
+ float depth_point[3];
+ madd_v3_v3v3fl(depth_point, view_origin, view_normal, depth_front);
+ for (int i = 0; i < tot_screen_points; i++) {
+ float new_point[3];
+ ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
+ copy_v3_v3(trim_operation->mesh->mvert[i].co, new_point);
+ copy_v3_v3(trim_operation->true_mesh_co[i], new_point);
+ }
+
+ /* Write vertices coordinates for the back face. */
+ madd_v3_v3v3fl(depth_point, view_origin, view_normal, depth_back);
+ for (int i = 0; i < tot_screen_points; i++) {
+ float new_point[3];
+ ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
+ copy_v3_v3(trim_operation->mesh->mvert[i + tot_screen_points].co, new_point);
+ copy_v3_v3(trim_operation->true_mesh_co[i + tot_screen_points], new_point);
+ }
+
+ /* Get the triangulation for the front/back poly. */
+ const int tot_tris_face = tot_screen_points - 2;
+ uint(*r_tris)[3] = MEM_malloc_arrayN(tot_tris_face, 3 * sizeof(uint), "tris");
+ BLI_polyfill_calc(screen_points, tot_screen_points, 0, r_tris);
+
+ /* Write the front face triangle indices. */
+ MPoly *mp = trim_operation->mesh->mpoly;
+ MLoop *ml = trim_operation->mesh->mloop;
+ for (int i = 0; i < tot_tris_face; i++, mp++, ml += 3) {
+ mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->totloop = 3;
+ ml[0].v = r_tris[i][0];
+ ml[1].v = r_tris[i][1];
+ ml[2].v = r_tris[i][2];
+ }
+
+ /* Write the back face triangle indices. */
+ for (int i = 0; i < tot_tris_face; i++, mp++, ml += 3) {
+ mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->totloop = 3;
+ ml[0].v = r_tris[i][0] + tot_screen_points;
+ ml[1].v = r_tris[i][1] + tot_screen_points;
+ ml[2].v = r_tris[i][2] + tot_screen_points;
+ }
+
+ MEM_freeN(r_tris);
+
+ /* Write the indices for the lateral triangles. */
+ for (int i = 0; i < tot_screen_points; i++, mp++, ml += 3) {
+ mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->totloop = 3;
+ int current_index = i;
+ int next_index = current_index + 1;
+ if (next_index >= tot_screen_points) {
+ next_index = 0;
+ }
+ ml[0].v = next_index + tot_screen_points;
+ ml[1].v = next_index;
+ ml[2].v = current_index;
+ }
+
+ for (int i = 0; i < tot_screen_points; i++, mp++, ml += 3) {
+ mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->totloop = 3;
+ int current_index = i;
+ int next_index = current_index + 1;
+ if (next_index >= tot_screen_points) {
+ next_index = 0;
+ }
+ ml[0].v = current_index;
+ ml[1].v = current_index + tot_screen_points;
+ ml[2].v = next_index + tot_screen_points;
+ }
+
+ BKE_mesh_calc_edges(trim_operation->mesh, false, false);
+ sculpt_gesture_trim_normals_update(sgcontext);
+}
+
+static void sculpt_gesture_trim_geometry_free(SculptGestureContext *sgcontext)
+{
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+ BKE_mesh_free(trim_operation->mesh);
+ MEM_freeN(trim_operation->true_mesh_co);
+}
+
+static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
+{
+ return BM_elem_flag_test(f, BM_ELEM_DRAW) ? 1 : 0;
+}
+
+static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
+{
+
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+ Object *object = sgcontext->vc.obact;
+ Mesh *sculpt_mesh = BKE_mesh_from_object(sgcontext->vc.obact);
+ Mesh *trim_mesh = trim_operation->mesh;
+
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh, trim_mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ trim_mesh,
+ &((struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ sculpt_mesh,
+ &((struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+ int tottri;
+ BMLoop *(*looptris)[3];
+ looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
+ BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
+
+ BMIter iter;
+ int i;
+ const int i_verts_end = trim_mesh->totvert;
+ const int i_faces_end = trim_mesh->totpoly;
+
+ float imat[4][4];
+ float omat[4][4];
+
+ invert_m4_m4(imat, object->obmat);
+ mul_m4_m4m4(omat, imat, object->obmat);
+
+ BMVert *eve;
+ i = 0;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ mul_m4_v3(omat, eve->co);
+ if (++i == i_verts_end) {
+ break;
+ }
+ }
+
+ /* We need face normals because of 'BM_face_split_edgenet'
+ * we could calculate on the fly too (before calling split). */
+ float nmat[3][3];
+ copy_m3_m4(nmat, omat);
+ invert_m3(nmat);
+
+ const short ob_src_totcol = trim_mesh->totcol;
+ short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1);
+
+ BMFace *efa;
+ i = 0;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ mul_transposed_m3_v3(nmat, efa->no);
+ normalize_v3(efa->no);
+
+ /* Temp tag to test which side split faces are from. */
+ BM_elem_flag_enable(efa, BM_ELEM_DRAW);
+
+ /* Remap material. */
+ if (efa->mat_nr < ob_src_totcol) {
+ efa->mat_nr = material_remap[efa->mat_nr];
+ }
+
+ if (++i == i_faces_end) {
+ break;
+ }
+ }
+
+ int boolean_mode;
+ switch (trim_operation->mode) {
+ case SCULPT_GESTURE_TRIM_INTERSECT:
+ boolean_mode = eBooleanModifierOp_Intersect;
+ break;
+ case SCULPT_GESTURE_TRIM_DIFFERENCE:
+ boolean_mode = eBooleanModifierOp_Difference;
+ break;
+ }
+
+ BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, false, boolean_mode);
+
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, sculpt_mesh);
+ BM_mesh_free(bm);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ BKE_mesh_nomain_to_mesh(result, sculpt_mesh, sgcontext->vc.obact, &CD_MASK_MESH, true);
+ BKE_mesh_free(result);
+}
+
+static void sculpt_gesture_trim_begin(bContext *C, SculptGestureContext *sgcontext)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ sculpt_gesture_trim_calculate_depth(sgcontext);
+ sculpt_gesture_trim_geometry_generate(sgcontext);
+ BKE_sculpt_update_object_for_edit(depsgraph, sgcontext->vc.obact, true, false, false);
+ SCULPT_undo_push_node(sgcontext->vc.obact, NULL, SCULPT_UNDO_GEOMETRY);
+}
+
+static void sculpt_gesture_trim_apply_for_symmetry_pass(bContext *UNUSED(C),
+ SculptGestureContext *sgcontext)
+{
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+ Mesh *trim_mesh = trim_operation->mesh;
+ for (int i = 0; i < trim_mesh->totvert; i++) {
+ flip_v3_v3(trim_mesh->mvert[i].co, trim_operation->true_mesh_co[i], sgcontext->symmpass);
+ }
+ sculpt_gesture_trim_normals_update(sgcontext);
+ sculpt_gesture_apply_trim(sgcontext);
+}
+
+static void sculpt_gesture_trim_end(bContext *UNUSED(C), SculptGestureContext *sgcontext)
+{
+ Object *object = sgcontext->vc.obact;
+ SculptSession *ss = object->sculpt;
+ ss->face_sets = CustomData_get_layer(&((Mesh *)object->data)->pdata, CD_SCULPT_FACE_SETS);
+ if (ss->face_sets) {
+ /* Assign a new Face Set ID to the new faces created by the trim operation. */
+ const int next_face_set_id = ED_sculpt_face_sets_find_next_available_id(object->data);
+ ED_sculpt_face_sets_initialize_none_to_id(object->data, next_face_set_id);
+ }
+
+ sculpt_gesture_trim_geometry_free(sgcontext);
+
+ SCULPT_undo_push_node(sgcontext->vc.obact, NULL, SCULPT_UNDO_GEOMETRY);
+ BKE_mesh_batch_cache_dirty_tag(sgcontext->vc.obact->data, BKE_MESH_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&sgcontext->vc.obact->id, ID_RECALC_GEOMETRY);
+}
+
+static void sculpt_gesture_init_trim_properties(SculptGestureContext *sgcontext, wmOperator *op)
+{
+ sgcontext->operation = MEM_callocN(sizeof(SculptGestureTrimOperation), "Trim Operation");
+
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+
+ trim_operation->op.sculpt_gesture_begin = sculpt_gesture_trim_begin;
+ trim_operation->op.sculpt_gesture_apply_for_symmetry_pass =
+ sculpt_gesture_trim_apply_for_symmetry_pass;
+ trim_operation->op.sculpt_gesture_end = sculpt_gesture_trim_end;
+
+ trim_operation->mode = RNA_enum_get(op->ptr, "trim_mode");
+}
+
+static void sculpt_trim_gesture_operator_properties(wmOperatorType *ot)
+{
+ RNA_def_enum(ot->srna,
+ "trim_mode",
+ prop_trim_operation_types,
+ SCULPT_GESTURE_TRIM_DIFFERENCE,
+ "Trim Mode",
+ NULL);
+}
+
static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op)
{
SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op);
@@ -747,6 +1143,45 @@ static int face_set_gesture_lasso_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op)
+{
+ Object *object = CTX_data_active_object(C);
+ SculptSession *ss = object->sculpt;
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ /* Not supported in Multires and Dyntopo. */
+ return OPERATOR_CANCELLED;
+ }
+
+ SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op);
+ if (!sgcontext) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_gesture_init_trim_properties(sgcontext, op);
+ sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_context_free(sgcontext);
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op)
+{
+ Object *object = CTX_data_active_object(C);
+ SculptSession *ss = object->sculpt;
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ /* Not supported in Multires and Dyntopo. */
+ return OPERATOR_CANCELLED;
+ }
+
+ SculptGestureContext *sgcontext = sculpt_gesture_init_from_lasso(C, op);
+ if (!sgcontext) {
+ return OPERATOR_CANCELLED;
+ }
+ sculpt_gesture_init_trim_properties(sgcontext, op);
+ sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_context_free(sgcontext);
+ return OPERATOR_FINISHED;
+}
+
void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
{
ot->name = "Mask Lasso Gesture";
@@ -826,3 +1261,45 @@ void SCULPT_OT_face_set_box_gesture(wmOperatorType *ot)
WM_operator_properties_border(ot);
sculpt_gesture_operator_properties(ot);
}
+
+void SCULPT_OT_trim_lasso_gesture(wmOperatorType *ot)
+{
+ ot->name = "Trim Lasso Gesture";
+ ot->idname = "SCULPT_OT_trim_lasso_gesture";
+ ot->description = "Trims the mesh within the lasso as you move the brush";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = sculpt_trim_gesture_lasso_exec;
+
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* Properties. */
+ WM_operator_properties_gesture_lasso(ot);
+ sculpt_gesture_operator_properties(ot);
+
+ sculpt_trim_gesture_operator_properties(ot);
+}
+
+void SCULPT_OT_trim_box_gesture(wmOperatorType *ot)
+{
+ ot->name = "Trim Box Gesture";
+ ot->idname = "SCULPT_OT_trim_box_gesture";
+ ot->description = "Trims the mesh within the box as you move the brush";
+
+ ot->invoke = WM_gesture_box_invoke;
+ ot->modal = WM_gesture_box_modal;
+ ot->exec = sculpt_trim_gesture_box_exec;
+
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* Properties. */
+ WM_operator_properties_border(ot);
+ sculpt_gesture_operator_properties(ot);
+
+ sculpt_trim_gesture_operator_properties(ot);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index f2eb1359af7..5070709cb6d 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -204,6 +204,14 @@ const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index)
return SCULPT_vertex_co_get(ss, index);
}
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index)
+{
+ if (ss->mvert) {
+ return ss->mvert[index].co;
+ }
+ return SCULPT_vertex_co_get(ss, index);
+}
+
void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -6694,7 +6702,8 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
if (tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- copy_v3_v3(cache->orig_grab_location, SCULPT_active_vertex_co_get(ss));
+ copy_v3_v3(cache->orig_grab_location,
+ SCULPT_vertex_co_for_grab_active_get(ss, SCULPT_active_vertex_get(ss)));
}
else {
copy_v3_v3(cache->orig_grab_location, cache->true_location);
@@ -8366,7 +8375,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
totpoints++;
if (!BLI_BITMAP_TEST(visited_vertices, to_v)) {
BLI_BITMAP_ENABLE(visited_vertices, to_v);
- const float *co = SCULPT_vertex_co_get(ss, to_v);
+ const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
if (len_squared_v3v3(brush_co, co) < radius * radius) {
BLI_gsqueue_push(not_visited_vertices, &to_v);
}
@@ -9155,6 +9164,8 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_face_sets_edit);
WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
WM_operatortype_append(SCULPT_OT_sample_color);
WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 5e01e034715..3051413a405 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -74,6 +74,10 @@ static bool boundary_initial_vertex_floodfill_cb(
{
BoundaryInitialVertexFloodFillData *data = userdata;
+ if (!SCULPT_vertex_visible_get(ss, to_v)) {
+ return false;
+ }
+
if (!is_duplicate) {
data->floodfill_steps[to_v] = data->floodfill_steps[from_v] + 1;
}
@@ -174,13 +178,19 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
const int initial_vertex)
{
+ if (!SCULPT_vertex_visible_get(ss, initial_vertex)) {
+ return false;
+ }
+
int neighbor_count = 0;
int boundary_vertex_count = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) {
- neighbor_count++;
- if (SCULPT_vertex_is_boundary(ss, ni.index)) {
- boundary_vertex_count++;
+ if (SCULPT_vertex_visible_get(ss, ni.index)) {
+ neighbor_count++;
+ if (SCULPT_vertex_is_boundary(ss, ni.index)) {
+ boundary_vertex_count++;
+ }
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -349,7 +359,9 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (boundary->edit_info[ni.index].num_propagation_steps == BOUNDARY_STEPS_NONE) {
+ const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index);
+ if (is_visible &&
+ boundary->edit_info[ni.index].num_propagation_steps == BOUNDARY_STEPS_NONE) {
boundary->edit_info[ni.index].original_vertex =
boundary->edit_info[from_v].original_vertex;
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index d7497a6cd4c..620033422b2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -100,6 +100,9 @@ const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
+/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+
/* Returns the info of the limit surface when Multires is available, otherwise it returns the
* current coordinate of the vertex. */
void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
@@ -1054,6 +1057,9 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot);
+void SCULPT_OT_trim_lasso_gesture(struct wmOperatorType *ot);
+void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot);
+
/* Face Sets. */
void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 87b84c475fd..9d9918a6daf 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -386,7 +386,9 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
specs,
container,
codec,
- bitrate);
+ bitrate,
+ NULL,
+ NULL);
}
else {
result = AUD_mixdown(scene_eval->sound_scene,
@@ -397,7 +399,9 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
specs,
container,
codec,
- bitrate);
+ bitrate,
+ NULL,
+ NULL);
}
BKE_sound_reset_scene_specs(scene_eval);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 301e88b0904..3650fbdc9f8 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -64,7 +64,7 @@
#include "UI_resources.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#define MAX_INFO_NUM_LEN 16
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 82f3b71eb32..9db89ec1ba2 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -116,12 +116,10 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr
static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiLayout *row, *col;
-
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayout *row = uiLayoutRow(col, true);
uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
if (ELEM(ntree->type, NTREE_COMPOSIT, NTREE_TEXTURE)) {
uiItemR(row, ptr, "use_alpha", DEFAULT_FLAGS, "", ICON_IMAGE_RGB_ALPHA);
@@ -132,7 +130,6 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiLayout *row;
#if 0
/* XXX no context access here .. */
bNode *node = ptr->data;
@@ -148,7 +145,7 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
- row = uiLayoutRow(layout, true);
+ uiLayout *row = uiLayoutRow(layout, true);
uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE);
uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
@@ -317,12 +314,9 @@ static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree,
{
const float margin = 1.5f * U.widget_unit;
NodeFrame *data = (NodeFrame *)node->storage;
- bool bbinit;
- bNode *tnode;
- rctf rect, noderect;
- float xmax, ymax;
/* init rect from current frame size */
+ rctf rect;
node_to_view(node, node->offsetx, node->offsety, &rect.xmin, &rect.ymax);
node_to_view(
node, node->offsetx + node->width, node->offsety - node->height, &rect.xmax, &rect.ymin);
@@ -330,15 +324,15 @@ static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree,
/* frame can be resized manually only if shrinking is disabled or no children are attached */
data->flag |= NODE_FRAME_RESIZEABLE;
/* for shrinking bbox, initialize the rect from first child node */
- bbinit = (data->flag & NODE_FRAME_SHRINK);
+ bool bbinit = (data->flag & NODE_FRAME_SHRINK);
/* fit bounding box to all children */
- for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+ LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
if (tnode->parent != node) {
continue;
}
/* add margin to node rect */
- noderect = tnode->totr;
+ rctf noderect = tnode->totr;
noderect.xmin -= margin;
noderect.xmax += margin;
noderect.ymin -= margin;
@@ -357,6 +351,7 @@ static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree,
/* now adjust the frame size from view-space bounding box */
node_from_view(node, rect.xmin, rect.ymax, &node->offsetx, &node->offsety);
+ float xmax, ymax;
node_from_view(node, rect.xmax, rect.ymin, &xmax, &ymax);
node->width = xmax - node->offsetx;
node->height = -ymax + node->offsety;
@@ -369,17 +364,9 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
/* XXX font id is crap design */
const int fontid = UI_style_get()->widgetlabel.uifont_id;
NodeFrame *data = (NodeFrame *)node->storage;
- rctf *rct = &node->totr;
- int color_id = node_get_colorid(node);
- char label[MAX_NAME];
- /* XXX a bit hacky, should use separate align values for x and y */
- float width, ascender;
- float x, y;
const int font_size = data->label_size / aspect;
- const float margin = (float)(NODE_DY / 4);
- int label_height;
- uchar color[3];
+ char label[MAX_NAME];
nodeLabel(ntree, node, label, sizeof(label));
BLF_enable(fontid, BLF_ASPECT);
@@ -388,16 +375,21 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
BLF_size(fontid, MIN2(24, font_size), U.dpi);
/* title color */
+ int color_id = node_get_colorid(node);
+ uchar color[3];
UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
BLF_color3ubv(fontid, color);
- width = BLF_width(fontid, label, sizeof(label));
- ascender = BLF_ascender(fontid);
- label_height = ((margin / aspect) + (ascender * aspect));
+ const float margin = (float)(NODE_DY / 4);
+ const float width = BLF_width(fontid, label, sizeof(label));
+ const float ascender = BLF_ascender(fontid);
+ const int label_height = ((margin / aspect) + (ascender * aspect));
/* 'x' doesn't need aspect correction */
- x = BLI_rctf_cent_x(rct) - (0.5f * width);
- y = rct->ymax - label_height;
+ rctf *rct = &node->totr;
+ /* XXX a bit hacky, should use separate align values for x and y */
+ float x = BLI_rctf_cent_x(rct) - (0.5f * width);
+ float y = rct->ymax - label_height;
BLF_position(fontid, x, y, 0);
BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
@@ -405,17 +397,15 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
/* draw text body */
if (node->id) {
Text *text = (Text *)node->id;
- TextLine *line;
const int line_height_max = BLF_height_max(fontid);
const float line_spacing = (line_height_max * aspect);
const float line_width = (BLI_rctf_size_x(rct) - margin) / aspect;
- int y_min;
/* 'x' doesn't need aspect correction */
x = rct->xmin + margin;
y = rct->ymax - (label_height + line_spacing);
/* early exit */
- y_min = y + ((margin * 2) - (y - rct->ymin));
+ int y_min = y + ((margin * 2) - (y - rct->ymin));
BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
BLF_clipping(fontid,
@@ -427,7 +417,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
BLF_wordwrap(fontid, line_width);
- for (line = text->lines.first; line; line = line->next) {
+ LISTBASE_FOREACH (TextLine *, line, &text->lines) {
struct ResultBLF info;
if (line->line[0]) {
BLF_position(fontid, x, y, 0);
@@ -455,9 +445,6 @@ static void node_draw_frame(const bContext *C,
bNode *node,
bNodeInstanceKey UNUSED(key))
{
- rctf *rct = &node->totr;
- float color[4];
- float alpha;
/* skip if out of view */
if (BLI_rctf_isect(&node->totr, &region->v2d.cur, NULL) == false) {
@@ -466,8 +453,9 @@ static void node_draw_frame(const bContext *C,
return;
}
+ float color[4];
UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- alpha = color[3];
+ const float alpha = color[3];
/* shadow */
node_draw_shadow(snode, node, BASIS_RAD, alpha);
@@ -480,6 +468,7 @@ static void node_draw_frame(const bContext *C,
UI_GetThemeColor4fv(TH_NODE_FRAME, color);
}
+ const rctf *rct = &node->totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
@@ -544,15 +533,12 @@ static void node_draw_reroute_prepare(const bContext *UNUSED(C),
bNodeTree *UNUSED(ntree),
bNode *node)
{
- bNodeSocket *nsock;
- float locx, locy;
- float size = NODE_REROUTE_SIZE;
-
/* get "global" coords */
+ float locx, locy;
node_to_view(node, 0.0f, 0.0f, &locx, &locy);
/* reroute node has exactly one input and one output, both in the same place */
- nsock = node->outputs.first;
+ bNodeSocket *nsock = node->outputs.first;
nsock->locx = locx;
nsock->locy = locy;
@@ -560,6 +546,7 @@ static void node_draw_reroute_prepare(const bContext *UNUSED(C),
nsock->locx = locx;
nsock->locy = locy;
+ const float size = NODE_REROUTE_SIZE;
node->width = size * 2;
node->totr.xmin = locx - size;
node->totr.xmax = locx + size;
@@ -687,18 +674,15 @@ static void node_buts_image_user(uiLayout *layout,
PointerRNA *iuserptr,
bool compositor)
{
- uiLayout *col;
- int source;
-
if (!imaptr->data) {
return;
}
- col = uiLayoutColumn(layout, false);
+ uiLayout *col = uiLayoutColumn(layout, false);
uiItemR(col, imaptr, "source", DEFAULT_FLAGS, "", ICON_NONE);
- source = RNA_enum_get(imaptr, "source");
+ const int source = RNA_enum_get(imaptr, "source");
if (source == IMA_SRC_SEQUENCE) {
/* don't use iuser->framenr directly
@@ -943,8 +927,8 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
bNode *node = ptr->data;
NodeShaderTexPointDensity *shader_point_density = node->storage;
Object *ob = (Object *)node->id;
- PointerRNA ob_ptr, obdata_ptr;
+ PointerRNA ob_ptr, obdata_ptr;
RNA_id_pointer_create((ID *)ob, &ob_ptr);
RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr);
@@ -1398,8 +1382,8 @@ static void node_buts_image_views(uiLayout *layout,
static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
- PointerRNA imaptr, iuserptr;
+ PointerRNA iuserptr;
RNA_pointer_create(ptr->owner_id, &RNA_ImageUser, node->storage, &iuserptr);
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(layout,
@@ -1416,7 +1400,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
return;
}
- imaptr = RNA_pointer_get(ptr, "image");
+ PointerRNA imaptr = RNA_pointer_get(ptr, "image");
node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true);
@@ -1426,8 +1410,8 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
- PointerRNA iuserptr;
+ PointerRNA iuserptr;
RNA_pointer_create(ptr->owner_id, &RNA_ImageUser, node->storage, &iuserptr);
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1);
@@ -1437,11 +1421,6 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
{
bNode *node = ptr->data;
uiLayout *col, *row;
- PointerRNA op_ptr;
- PointerRNA scn_ptr;
- PropertyRNA *prop;
- const char *layer_name;
- char scene_name[MAX_ID_NAME - 2];
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
@@ -1453,15 +1432,19 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
row = uiLayoutRow(col, true);
uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
- prop = RNA_struct_find_property(ptr, "layer");
+ PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
+ const char *layer_name;
if (!(RNA_property_enum_identifier(
C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
return;
}
+ PointerRNA scn_ptr;
+ char scene_name[MAX_ID_NAME - 2];
scn_ptr = RNA_pointer_get(ptr, "scene");
RNA_string_get(&scn_ptr, "name", scene_name);
+ PointerRNA op_ptr;
uiItemFullO(
row, "RENDER_OT_render", "", ICON_RENDER_STILL, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_string_set(&op_ptr, "layer", layer_name);
@@ -1471,12 +1454,10 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col, *row;
- int reference;
- int filter;
col = uiLayoutColumn(layout, false);
- filter = RNA_enum_get(ptr, "filter_type");
- reference = RNA_boolean_get(ptr, "use_variable_size");
+ const int filter = RNA_enum_get(ptr, "filter_type");
+ const int reference = RNA_boolean_get(ptr, "use_variable_size");
uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
if (filter != R_FILTER_FAST_GAUSS) {
@@ -1925,9 +1906,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
- wmOperatorType *ot;
uiLayout *row, *col;
- int active_index;
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
@@ -1947,7 +1926,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
row = uiLayoutRow(layout, false);
col = uiLayoutColumn(row, true);
- active_index = RNA_int_get(ptr, "active_input_index");
+ const int active_index = RNA_int_get(ptr, "active_input_index");
/* using different collection properties if multilayer format is enabled */
if (multilayer) {
uiTemplateList(col,
@@ -1992,7 +1971,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
active_input_ptr.owner_id = ptr->owner_id;
col = uiLayoutColumn(row, true);
- ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_enum_set(&op_ptr, "direction", 1);
uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
@@ -3435,13 +3414,12 @@ static void node_file_output_socket_draw(bContext *C,
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = ptr->data;
uiLayout *row;
- PointerRNA inputptr, imfptr;
- int imtype;
+ PointerRNA inputptr;
row = uiLayoutRow(layout, false);
- imfptr = RNA_pointer_get(node_ptr, "format");
- imtype = RNA_enum_get(&imfptr, "file_format");
+ PointerRNA imfptr = RNA_pointer_get(node_ptr, "format");
+ int imtype = RNA_enum_get(&imfptr, "file_format");
if (imtype == R_IMF_IMTYPE_MULTILAYER) {
NodeImageMultiFileSocket *input = sock->storage;
@@ -3451,8 +3429,6 @@ static void node_file_output_socket_draw(bContext *C,
}
else {
NodeImageMultiFileSocket *input = sock->storage;
- PropertyRNA *imtype_prop;
- const char *imtype_name;
uiBlock *block;
RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotFile, input, &inputptr);
@@ -3462,7 +3438,8 @@ static void node_file_output_socket_draw(bContext *C,
imfptr = RNA_pointer_get(&inputptr, "format");
}
- imtype_prop = RNA_struct_find_property(&imfptr, "file_format");
+ const char *imtype_name;
+ PropertyRNA *imtype_prop = RNA_struct_find_property(&imfptr, "file_format");
RNA_property_enum_name((bContext *)C,
&imfptr,
imtype_prop,
@@ -3611,9 +3588,6 @@ void draw_nodespace_back_pix(const bContext *C,
bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key :
NODE_INSTANCE_KEY_NONE);
float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- Image *ima;
- void *lock;
- ImBuf *ibuf;
GPU_matrix_push_projection();
GPU_matrix_push();
@@ -3631,19 +3605,18 @@ void draw_nodespace_back_pix(const bContext *C,
return;
}
- ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ void *lock;
+ Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
if (ibuf) {
- float x, y;
-
GPU_matrix_push_projection();
GPU_matrix_push();
/* somehow the offset has to be calculated inverse */
wmOrtho2_region_pixelspace(region);
- x = (region->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
- y = (region->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
+ const float x = (region->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
+ const float y = (region->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
if (ibuf->rect || ibuf->rect_float) {
uchar *display_buffer = NULL;
@@ -3746,10 +3719,7 @@ static bool node_link_bezier_handles(View2D *v2d,
bNodeLink *link,
float vec[4][2])
{
- float dist;
- float deltax, deltay;
float cursor[2] = {0.0f, 0.0f};
- int toreroute, fromreroute;
/* this function can be called with snode null (via cut_links_intersect) */
/* XXX map snode->cursor back to view space */
@@ -3759,6 +3729,7 @@ static bool node_link_bezier_handles(View2D *v2d,
}
/* in v0 and v3 we put begin/end points */
+ int toreroute, fromreroute;
if (link->fromsock) {
vec[0][0] = link->fromsock->locx;
vec[0][1] = link->fromsock->locy;
@@ -3794,9 +3765,9 @@ static bool node_link_bezier_handles(View2D *v2d,
return true;
}
- dist = curving * 0.10f * fabsf(vec[0][0] - vec[3][0]);
- deltax = vec[3][0] - vec[0][0];
- deltay = vec[3][1] - vec[0][1];
+ const float dist = curving * 0.10f * fabsf(vec[0][0] - vec[3][0]);
+ const float deltax = vec[3][0] - vec[0][0];
+ const float deltay = vec[3][1] - vec[0][1];
/* check direction later, for top sockets */
if (fromreroute) {
if (fabsf(deltax) > fabsf(deltay)) {
@@ -3850,9 +3821,9 @@ bool node_link_bezier_points(
BKE_curve_forward_diff_bezier(
vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0] + 1, resol, sizeof(float[2]));
- return 1;
+ return true;
}
- return 0;
+ return false;
}
#define NODELINK_GROUP_SIZE 256
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index ba6b164704f..fc4685929d3 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -175,7 +175,6 @@ void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
static bool compare_nodes(const bNode *a, const bNode *b)
{
- bNode *parent;
/* These tell if either the node or any of the parent nodes is selected.
* A selected parent means an unselected node is also in foreground!
*/
@@ -185,7 +184,7 @@ static bool compare_nodes(const bNode *a, const bNode *b)
/* if one is an ancestor of the other */
/* XXX there might be a better sorting algorithm for stable topological sort,
* this is O(n^2) worst case */
- for (parent = a->parent; parent; parent = parent->parent) {
+ for (bNode *parent = a->parent; parent; parent = parent->parent) {
/* if b is an ancestor, it is always behind a */
if (parent == b) {
return true;
@@ -198,7 +197,7 @@ static bool compare_nodes(const bNode *a, const bNode *b)
a_select = 1;
}
}
- for (parent = b->parent; parent; parent = parent->parent) {
+ for (bNode *parent = b->parent; parent; parent = parent->parent) {
/* if a is an ancestor, it is always behind b */
if (parent == a) {
return false;
@@ -237,17 +236,16 @@ static bool compare_nodes(const bNode *a, const bNode *b)
void ED_node_sort(bNodeTree *ntree)
{
/* merge sort is the algorithm of choice here */
- bNode *first_a, *first_b, *node_a, *node_b, *tmp;
int totnodes = BLI_listbase_count(&ntree->nodes);
- int k, a, b;
- k = 1;
+ int k = 1;
while (k < totnodes) {
- first_a = first_b = ntree->nodes.first;
+ bNode *first_a = ntree->nodes.first;
+ bNode *first_b = first_a;
do {
/* setup first_b pointer */
- for (b = 0; b < k && first_b; b++) {
+ for (int b = 0; b < k && first_b; b++) {
first_b = first_b->next;
}
/* all batches merged? */
@@ -256,16 +254,17 @@ void ED_node_sort(bNodeTree *ntree)
}
/* merge batches */
- node_a = first_a;
- node_b = first_b;
- a = b = 0;
+ bNode *node_a = first_a;
+ bNode *node_b = first_b;
+ int a = 0;
+ int b = 0;
while (a < k && b < k && node_b) {
if (compare_nodes(node_a, node_b) == 0) {
node_a = node_a->next;
a++;
}
else {
- tmp = node_b;
+ bNode *tmp = node_b;
node_b = node_b->next;
b++;
BLI_remlink(&ntree->nodes, tmp);
@@ -301,13 +300,12 @@ static void do_node_internal_buttons(bContext *C, void *UNUSED(node_v), int even
static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
{
- bNode *node;
- char uiblockstr[32];
/* add node uiBlocks in drawing order - prevents events going to overlapping nodes */
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
/* ui block */
+ char uiblockstr[32];
BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
UI_block_func_handle_set(node->block, do_node_internal_buttons, node);
@@ -345,17 +343,14 @@ void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
{
uiLayout *layout, *row;
- PointerRNA nodeptr, sockptr;
- bNodeSocket *nsock;
- float locx, locy;
- float dy;
- int buty;
+ PointerRNA nodeptr;
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
/* get "global" coords */
+ float locx, locy;
node_to_view(node, 0.0f, 0.0f, &locx, &locy);
- dy = locy;
+ float dy = locy;
/* header */
dy -= NODE_DY;
@@ -368,11 +363,13 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
/* output sockets */
bool add_output_space = false;
- for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
+ int buty;
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
+ PointerRNA sockptr;
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
layout = UI_block_layout(node->block,
@@ -495,11 +492,12 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
/* input sockets */
- for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
+ PointerRNA sockptr;
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
layout = UI_block_layout(node->block,
@@ -564,27 +562,26 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
/* based on settings in node, sets drawing rect info. each redraw! */
static void node_update_hidden(bNode *node)
{
- bNodeSocket *nsock;
- float locx, locy;
- float rad, drad, hiddenrad = HIDDEN_RAD;
- int totin = 0, totout = 0, tot;
+ int totin = 0, totout = 0;
/* get "global" coords */
+ float locx, locy;
node_to_view(node, 0.0f, 0.0f, &locx, &locy);
/* calculate minimal radius */
- for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
if (!nodeSocketIsHidden(nsock)) {
totin++;
}
}
- for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
if (!nodeSocketIsHidden(nsock)) {
totout++;
}
}
- tot = MAX2(totin, totout);
+ float hiddenrad = HIDDEN_RAD;
+ float tot = MAX2(totin, totout);
if (tot > 4) {
hiddenrad += 5.0f * (float)(tot - 4);
}
@@ -595,9 +592,10 @@ static void node_update_hidden(bNode *node)
node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
/* output sockets */
- rad = drad = (float)M_PI / (1.0f + (float)totout);
+ float rad = (float)M_PI / (1.0f + (float)totout);
+ float drad = rad;
- for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
if (!nodeSocketIsHidden(nsock)) {
nsock->locx = node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad;
nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
@@ -608,7 +606,7 @@ static void node_update_hidden(bNode *node)
/* input sockets */
rad = drad = -(float)M_PI / (1.0f + (float)totin);
- for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
if (!nodeSocketIsHidden(nsock)) {
nsock->locx = node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad;
nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
@@ -689,11 +687,9 @@ int node_get_colorid(bNode *node)
/* note: in node_edit.c is similar code, for untangle node */
static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
{
- bNodeLink *link;
-
GPU_blend(GPU_BLEND_ALPHA);
- for (link = node->internal_links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
}
@@ -892,10 +888,9 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
float xscale = xrect / ((float)preview->xsize);
float yscale = yrect / ((float)preview->ysize);
float scale;
- rctf draw_rect;
/* uniform scale and offset */
- draw_rect = *prv;
+ rctf draw_rect = *prv;
if (xscale < yscale) {
float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale);
draw_rect.ymin += offset;
@@ -1127,14 +1122,9 @@ static void node_draw_basis(const bContext *C,
bNode *node,
bNodeInstanceKey key)
{
- bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
- rctf *rct = &node->totr;
- float iconofs;
/* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
float iconbutw = 0.8f * UI_UNIT_X;
- int color_id = node_get_colorid(node);
- float color[4];
- char showname[128]; /* 128 used below */
+
View2D *v2d = &region->v2d;
/* skip if out of view */
@@ -1147,6 +1137,8 @@ static void node_draw_basis(const bContext *C,
/* shadow */
node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
+ float color[4];
+ int color_id = node_get_colorid(node);
if (node->flag & NODE_MUTED) {
/* Muted nodes are semi-transparent and colorless. */
UI_GetThemeColor3fv(TH_NODE, color);
@@ -1160,12 +1152,13 @@ static void node_draw_basis(const bContext *C,
GPU_line_width(1.0f);
+ rctf *rct = &node->totr;
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
UI_draw_roundbox_aa(
true, rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color);
/* show/hide icons */
- iconofs = rct->xmax - 0.35f * U.widget_unit;
+ float iconofs = rct->xmax - 0.35f * U.widget_unit;
/* preview */
if (node->typeinfo->flag & NODE_PREVIEW) {
@@ -1273,6 +1266,7 @@ static void node_draw_basis(const bContext *C,
UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color);
}
+ char showname[128]; /* 128 used below */
nodeLabel(ntree, node, showname, sizeof(showname));
uiBut *but = uiDefBut(node->block,
@@ -1334,6 +1328,7 @@ static void node_draw_basis(const bContext *C,
node_draw_sockets(v2d, C, ntree, node, true, false);
/* preview */
+ bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
if (node->flag & NODE_PREVIEW && previews) {
bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key);
if (preview && (preview->xsize && preview->ysize)) {
@@ -1356,20 +1351,20 @@ static void node_draw_hidden(const bContext *C,
bNodeInstanceKey UNUSED(key))
{
rctf *rct = &node->totr;
- float dx, centy = BLI_rctf_cent_y(rct);
+ float centy = BLI_rctf_cent_y(rct);
float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
- int color_id = node_get_colorid(node);
- float color[4];
- char showname[128]; /* 128 is used below */
+
View2D *v2d = &region->v2d;
- float scale;
+ float scale;
UI_view2d_scale_get(v2d, &scale, NULL);
/* shadow */
node_draw_shadow(snode, node, hiddenrad, 1.0f);
/* body */
+ float color[4];
+ int color_id = node_get_colorid(node);
if (node->flag & NODE_MUTED) {
/* Muted nodes are semi-transparent and colorless. */
UI_GetThemeColor4fv(TH_NODE, color);
@@ -1448,6 +1443,7 @@ static void node_draw_hidden(const bContext *C,
node_draw_mute_line(&region->v2d, snode, node);
}
+ char showname[128]; /* 128 is used below */
nodeLabel(ntree, node, showname, sizeof(showname));
/* XXX - don't print into self! */
@@ -1477,7 +1473,7 @@ static void node_draw_hidden(const bContext *C,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColorShade(color_id, -10);
- dx = 10.0f;
+ float dx = 10.0f;
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
@@ -1573,13 +1569,11 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
void node_update_nodetree(const bContext *C, bNodeTree *ntree)
{
- bNode *node;
-
/* make sure socket "used" tags are correct, for displaying value buttons */
ntreeTagUsedSockets(ntree);
/* update nodes front to back, so children sizes get updated before parents */
- for (node = ntree->nodes.last; node; node = node->prev) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
node_update(C, ntree, node);
}
}
@@ -1604,10 +1598,6 @@ void node_draw_nodetree(const bContext *C,
bNodeTree *ntree,
bNodeInstanceKey parent_key)
{
- bNode *node;
- bNodeLink *link;
- int a;
-
if (ntree == NULL) {
return; /* groups... */
}
@@ -1619,6 +1609,8 @@ void node_draw_nodetree(const bContext *C,
#endif
/* draw background nodes, last nodes in front */
+ int a;
+ bNode *node;
for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
bNodeInstanceKey key;
@@ -1640,7 +1632,7 @@ void node_draw_nodetree(const bContext *C,
/* node lines */
GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode);
- for (link = ntree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (!nodeLinkIsHidden(link)) {
node_draw_link(&region->v2d, snode, link);
}
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 83ccfa65af3..5f3047fbdc2 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -32,6 +32,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
@@ -1163,6 +1164,16 @@ void NODE_OT_select_same_type_step(wmOperatorType *ot)
/** \name Find Node by Name Operator
* \{ */
+static void node_find_create_label(const bNode *node, char *str, int maxlen)
+{
+ if (node->label[0]) {
+ BLI_snprintf(str, maxlen, "%s (%s)", node->name, node->label);
+ }
+ else {
+ BLI_strncpy(str, node->name, maxlen);
+ }
+}
+
/* generic search invoke */
static void node_find_update_fn(const struct bContext *C,
void *UNUSED(arg),
@@ -1170,30 +1181,29 @@ static void node_find_update_fn(const struct bContext *C,
uiSearchItems *items)
{
SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node;
- /* Prepare BLI_string_all_words_matched. */
- const size_t str_len = strlen(str);
- const int words_max = BLI_string_max_possible_word_count(str_len);
- int(*words)[2] = BLI_array_alloca(words, words_max);
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+ StringSearch *search = BLI_string_search_new();
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- if (BLI_string_all_words_matched(node->name, str, words, words_len) ||
- BLI_string_all_words_matched(node->label, str, words, words_len)) {
- char name[256];
+ LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ char name[256];
+ node_find_create_label(node, name, ARRAY_SIZE(name));
+ BLI_string_search_add(search, name, node);
+ }
- if (node->label[0]) {
- BLI_snprintf(name, 256, "%s (%s)", node->name, node->label);
- }
- else {
- BLI_strncpy(name, node->name, 256);
- }
- if (!UI_search_item_add(items, name, node, ICON_NONE, 0, 0)) {
- break;
- }
+ bNode **filtered_nodes;
+ int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_nodes);
+
+ for (int i = 0; i < filtered_amount; i++) {
+ bNode *node = filtered_nodes[i];
+ char name[256];
+ node_find_create_label(node, name, ARRAY_SIZE(name));
+ if (!UI_search_item_add(items, name, node, ICON_NONE, 0, 0)) {
+ break;
}
}
+
+ MEM_freeN(filtered_nodes);
+ BLI_string_search_free(search);
}
static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2)
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index bb9574ee55e..833f40730ad 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -61,7 +61,7 @@ typedef struct TextFormatType {
char (*format_identifier)(const char *string);
/* Formats the specified line. If do_next is set, the process will move on to
- * the succeeding line if it is affected (eg. multiline strings). Format strings
+ * the succeeding line if it is affected (eg. multi-line strings). Format strings
* may contain any of the following characters:
*
* It is terminated with a null-terminator '\0' followed by a continuation
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index c4da39bca2f..da44815b31a 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -879,14 +879,14 @@ float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
const void *usys;
int len;
- bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
+ BKE_unit_system_get(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
if (usys) {
- int i = bUnit_GetBaseUnit(usys);
+ int i = BKE_unit_base_get(usys);
if (r_grid_unit) {
- *r_grid_unit = bUnit_GetNameDisplay(usys, i);
+ *r_grid_unit = BKE_unit_display_name_get(usys, i);
}
- return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
+ return (float)BKE_unit_scalar_get(usys, i) / scene->unit.scale_length;
}
}
@@ -906,20 +906,20 @@ void ED_view3d_grid_steps(const Scene *scene,
{
const void *usys;
int i, len;
- bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
+ BKE_unit_system_get(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
float grid_scale = v3d->grid;
BLI_assert(STEPS_LEN >= len);
if (usys) {
if (rv3d->view == RV3D_VIEW_USER) {
/* Skip steps */
- len = bUnit_GetBaseUnit(usys) + 1;
+ len = BKE_unit_base_get(usys) + 1;
}
grid_scale /= scene->unit.scale_length;
for (i = 0; i < len; i++) {
- r_grid_steps[i] = (float)bUnit_GetScaler(usys, len - 1 - i) * grid_scale;
+ r_grid_steps[i] = (float)BKE_unit_scalar_get(usys, len - 1 - i) * grid_scale;
}
for (; i < STEPS_LEN; i++) {
/* Fill last slots */
@@ -971,10 +971,10 @@ float ED_view3d_grid_view_scale(Scene *scene,
if (r_grid_unit) {
const void *usys;
int len;
- bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
+ BKE_unit_system_get(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
if (usys) {
- *r_grid_unit = bUnit_GetNameDisplay(usys, len - i - 1);
+ *r_grid_unit = BKE_unit_display_name_get(usys, len - i - 1);
}
}
}
@@ -2157,8 +2157,13 @@ static void view3d_opengl_read_Z_pixels(GPUViewport *viewport, rcti *rect, void
GPU_framebuffer_texture_attach(tmp_fb, dtxl->depth, 0, 0);
GPU_framebuffer_bind(tmp_fb);
- GPU_framebuffer_read_depth(
- tmp_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), data);
+ GPU_framebuffer_read_depth(tmp_fb,
+ rect->xmin,
+ rect->ymin,
+ BLI_rcti_size_x(rect),
+ BLI_rcti_size_y(rect),
+ GPU_DATA_FLOAT,
+ data);
GPU_framebuffer_restore();
GPU_framebuffer_free(tmp_fb);
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 5aba1fecc53..990b7952e39 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -179,7 +179,7 @@ static void ruler_item_as_string(
BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle));
}
else {
- bUnit_AsString2(
+ BKE_unit_value_as_string(
numstr, numstr_size, (double)ruler_angle, prec, B_UNIT_ROTATION, unit, false);
}
}
@@ -190,13 +190,13 @@ static void ruler_item_as_string(
BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
}
else {
- bUnit_AsString2(numstr,
- numstr_size,
- (double)(ruler_len * unit->scale_length),
- prec,
- B_UNIT_LENGTH,
- unit,
- false);
+ BKE_unit_value_as_string(numstr,
+ numstr_size,
+ (double)(ruler_len * unit->scale_length),
+ prec,
+ B_UNIT_LENGTH,
+ unit,
+ false);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 632769c167e..92447c257da 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -322,6 +322,8 @@ void createTransUVs(bContext *C, TransInfo *t)
}
}
+ float *prop_dists = NULL;
+
/* Support other objects using PET to adjust these, unless connected is enabled. */
if (((is_prop_edit && !is_prop_connected) ? count : countsel) == 0) {
goto finally;
@@ -349,8 +351,6 @@ void createTransUVs(bContext *C, TransInfo *t)
td = tc->data;
td2d = tc->data_2d;
- float *prop_dists = NULL;
-
if (is_prop_connected) {
prop_dists = MEM_callocN(em->bm->totloop * sizeof(float), "TransObPropDists(UV Editing)");
@@ -397,7 +397,7 @@ void createTransUVs(bContext *C, TransInfo *t)
finally:
if (is_prop_connected) {
- MEM_freeN(prop_dists);
+ MEM_SAFE_FREE(prop_dists);
}
if (is_island_center) {
BM_uv_element_map_free(elementmap);
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 36be26049d3..866b9d921c8 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -89,13 +89,13 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
dist = len_v3(vec);
if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
for (int i = 0; i < 3; i++) {
- bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i],
- NUM_STR_REP_LEN,
- dvec[i] * t->scene->unit.scale_length,
- 4,
- B_UNIT_LENGTH,
- &t->scene->unit,
- true);
+ BKE_unit_value_as_string(&tvec[NUM_STR_REP_LEN * i],
+ NUM_STR_REP_LEN,
+ dvec[i] * t->scene->unit.scale_length,
+ 4,
+ B_UNIT_LENGTH,
+ &t->scene->unit,
+ true);
}
}
else {
@@ -106,13 +106,13 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
- bUnit_AsString2(distvec,
- sizeof(distvec),
- dist * t->scene->unit.scale_length,
- 4,
- B_UNIT_LENGTH,
- &t->scene->unit,
- false);
+ BKE_unit_value_as_string(distvec,
+ sizeof(distvec),
+ dist * t->scene->unit.scale_length,
+ 4,
+ B_UNIT_LENGTH,
+ &t->scene->unit,
+ false);
}
else if (dist > 1e10f || dist < -1e10f) {
/* prevent string buffer overflow */
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 041b2fec00b..ba22bcca0e1 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -136,14 +136,14 @@ void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
BLI_strncpy(val, "Invalid", sizeof(val));
}
else {
- bUnit_AsString(val,
- sizeof(val),
- (double)(n->val[i] * fac),
- prec,
- n->unit_sys,
- n->unit_type[i],
- true,
- false);
+ BKE_unit_value_as_string_adaptive(val,
+ sizeof(val),
+ (double)(n->val[i] * fac),
+ prec,
+ n->unit_sys,
+ n->unit_type[i],
+ true,
+ false);
}
/* +1 because of trailing '\0' */
@@ -165,7 +165,7 @@ void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
}
else {
char tstr[NUM_STR_REP_LEN];
- bUnit_AsString(
+ BKE_unit_value_as_string_adaptive(
tstr, ln, (double)n->val[i], prec, n->unit_sys, n->unit_type[i], true, false);
BLI_snprintf(&str[j * ln], ln, "%s%s%s", cur, tstr, cur);
}
@@ -252,14 +252,14 @@ bool applyNumInput(NumInput *n, float *vec)
static void value_to_editstr(NumInput *n, int idx)
{
const int prec = 6; /* editing, higher precision needed. */
- n->str_cur = bUnit_AsString(n->str,
- NUM_STR_REP_LEN,
- (double)n->val[idx],
- prec,
- n->unit_sys,
- n->unit_type[idx],
- true,
- false);
+ n->str_cur = BKE_unit_value_as_string_adaptive(n->str,
+ NUM_STR_REP_LEN,
+ (double)n->val[idx],
+ prec,
+ n->unit_sys,
+ n->unit_type[idx],
+ true,
+ false);
}
static bool editstr_insert_at_cursor(NumInput *n, const char *buf, const int buf_len)
@@ -288,17 +288,17 @@ bool user_string_to_number(bContext *C,
{
#ifdef WITH_PYTHON
double unit_scale = BKE_scene_unit_scale(unit, type, 1.0);
- if (bUnit_ContainsUnit(str, type)) {
+ if (BKE_unit_string_contains_unit(str, type)) {
char str_unit_convert[256];
BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
- bUnit_ReplaceString(
+ BKE_unit_replace_string(
str_unit_convert, sizeof(str_unit_convert), str, unit_scale, unit->system, type);
return BPY_run_string_as_number(C, NULL, str_unit_convert, error_prefix, r_value);
}
int success = BPY_run_string_as_number(C, NULL, str, error_prefix, r_value);
- *r_value *= bUnit_PreferredInputUnitScalar(unit, type);
+ *r_value = BKE_unit_apply_preferred_unit(unit, type, *r_value);
*r_value /= unit_scale;
return success;
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 49f11cd6a74..f043dc92624 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -261,7 +261,7 @@ static void construct_param_handle_face_add(ParamHandle *handle,
key = (ParamKey)face_index;
/* let parametrizer split the ngon, it can make better decisions
- * about which split is best for unwrapping than scanfill */
+ * about which split is best for unwrapping than poly-fill. */
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
index 5db75c84608..c329a3badd5 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
@@ -36,7 +36,7 @@ PyDoc_STRVAR(FEdgeSharp_doc,
"\n"
"Class defining a sharp FEdge. A Sharp FEdge corresponds to an initial\n"
"edge of the input mesh. It can be a silhouette, a crease or a border.\n"
- "If it is a crease edge, then it is borded by two faces of the mesh.\n"
+ "If it is a crease edge, then it is bordered by two faces of the mesh.\n"
"Face a lies on its right whereas Face b lies on its left. If it is a\n"
"border edge, then it doesn't have any face on its right, and thus Face\n"
"a is None.\n"
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
index 21bd371935a..734aa5a0e84 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
@@ -34,7 +34,7 @@ static char ContourUP1D___doc__[] =
".. method:: __call__(inter)\n"
"\n"
" Returns true if the Interface1D is a contour. An Interface1D is a\n"
- " contour if it is borded by a different shape on each of its sides.\n"
+ " contour if it is bordered by a different shape on each of its sides.\n"
"\n"
" :arg inter: An Interface1D object.\n"
" :type inter: :class:`freestyle.types.Interface1D`\n"
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
index ea034dfad1e..3ddadcf2d4f 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
@@ -34,7 +34,7 @@ static char ExternalContourUP1D___doc__[] =
".. method:: __call__(inter)\n"
"\n"
" Returns true if the Interface1D is an external contour. An\n"
- " Interface1D is an external contour if it is borded by no shape on\n"
+ " Interface1D is an external contour if it is bordered by no shape on\n"
" one of its sides.\n"
"\n"
" :arg inter: An Interface1D object.\n"
diff --git a/source/blender/freestyle/intern/stroke/Predicates1D.h b/source/blender/freestyle/intern/stroke/Predicates1D.h
index a3953950d86..c174162b214 100644
--- a/source/blender/freestyle/intern/stroke/Predicates1D.h
+++ b/source/blender/freestyle/intern/stroke/Predicates1D.h
@@ -218,7 +218,7 @@ class QuantitativeInvisibilityUP1D : public UnaryPredicate1D {
// ContourUP1D
/*! Returns true if the Interface1D is a contour.
- * An Interface1D is a contour if it is borded by a different shape on each of its sides.
+ * An Interface1D is a contour if it is bordered by a different shape on each of its sides.
*/
class ContourUP1D : public UnaryPredicate1D {
private:
@@ -253,7 +253,7 @@ class ContourUP1D : public UnaryPredicate1D {
// ExternalContourUP1D
/*! Returns true if the Interface1D is an external contour.
- * An Interface1D is an external contour if it is borded by no shape on one of its sides.
+ * An Interface1D is an external contour if it is bordered by no shape on one of its sides.
*/
class ExternalContourUP1D : public UnaryPredicate1D {
private:
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index c27d6b633b4..5a59f488b51 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1139,7 +1139,7 @@ Interface0DIterator FEdge::pointsEnd(float /*t*/)
}
/*! Class defining a sharp FEdge. A Sharp FEdge corresponds to an initial edge of the input mesh.
- * It can be a silhouette, a crease or a border. If it is a crease edge, then it is borded
+ * It can be a silhouette, a crease or a border. If it is a crease edge, then it is bordered
* by two faces of the mesh. Face a lies on its right whereas Face b lies on its left.
* If it is a border edge, then it doesn't have any face on its right, and thus Face a = 0.
*/
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 5cce4f84aea..bb50cd3744f 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -59,11 +59,11 @@ set(SRC
intern/gpu_batch_presets.c
intern/gpu_batch_utils.c
intern/gpu_buffers.c
+ intern/gpu_capabilities.cc
intern/gpu_codegen.c
intern/gpu_context.cc
intern/gpu_debug.cc
intern/gpu_drawlist.cc
- intern/gpu_extensions.cc
intern/gpu_framebuffer.cc
intern/gpu_immediate.cc
intern/gpu_immediate_util.c
@@ -74,9 +74,10 @@ set(SRC
intern/gpu_matrix.cc
intern/gpu_node_graph.c
intern/gpu_platform.cc
+ intern/gpu_query.cc
intern/gpu_select.c
intern/gpu_select_pick.c
- intern/gpu_select_sample_query.c
+ intern/gpu_select_sample_query.cc
intern/gpu_shader.cc
intern/gpu_shader_builtin.c
intern/gpu_shader_interface.cc
@@ -87,6 +88,7 @@ set(SRC
intern/gpu_vertex_format.cc
intern/gpu_viewport.c
+ opengl/gl_backend.cc
opengl/gl_batch.cc
opengl/gl_context.cc
opengl/gl_drawlist.cc
@@ -94,6 +96,7 @@ set(SRC
opengl/gl_framebuffer.cc
opengl/gl_immediate.cc
opengl/gl_index_buffer.cc
+ opengl/gl_query.cc
opengl/gl_shader.cc
opengl/gl_shader_interface.cc
opengl/gl_state.cc
@@ -106,11 +109,11 @@ set(SRC
GPU_batch_presets.h
GPU_batch_utils.h
GPU_buffers.h
+ GPU_capabilities.h
GPU_common.h
GPU_context.h
GPU_debug.h
GPU_drawlist.h
- GPU_extensions.h
GPU_framebuffer.h
GPU_glew.h
GPU_immediate.h
@@ -133,6 +136,7 @@ set(SRC
intern/gpu_backend.hh
intern/gpu_batch_private.hh
+ intern/gpu_capabilities_private.hh
intern/gpu_codegen.h
intern/gpu_context_private.hh
intern/gpu_drawlist_private.hh
@@ -143,6 +147,8 @@ set(SRC
intern/gpu_matrix_private.h
intern/gpu_node_graph.h
intern/gpu_private.h
+ intern/gpu_platform_private.hh
+ intern/gpu_query.hh
intern/gpu_select_private.h
intern/gpu_shader_private.hh
intern/gpu_shader_interface.hh
@@ -161,6 +167,7 @@ set(SRC
opengl/gl_immediate.hh
opengl/gl_index_buffer.hh
opengl/gl_primitive.hh
+ opengl/gl_query.hh
opengl/gl_shader.hh
opengl/gl_shader_interface.hh
opengl/gl_state.hh
@@ -372,3 +379,19 @@ if(WITH_IMAGE_DDS)
endif()
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ if(WITH_OPENGL_DRAW_TESTS)
+ set(TEST_SRC
+ tests/gpu_testing.cc
+ )
+ set(TEST_INC
+ "../../../intern/ghost/"
+ )
+ set(TEST_LIB
+
+ )
+ include(GTestTesting)
+ blender_add_test_lib(bf_gpu_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+ endif()
+endif()
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_capabilities.h
index 35967ac304f..b8a48735548 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -19,6 +19,10 @@
/** \file
* \ingroup gpu
+ *
+ * GPU Capabilities & workarounds
+ * This module expose the reported implementation limits & enabled
+ * workaround for drivers that needs specific codepaths.
*/
#pragma once
@@ -27,37 +31,23 @@
extern "C" {
#endif
-/* GPU extensions support */
-
int GPU_max_texture_size(void);
-int GPU_max_texture_3d_size(void);
int GPU_max_texture_layers(void);
int GPU_max_textures(void);
int GPU_max_textures_vert(void);
int GPU_max_textures_geom(void);
int GPU_max_textures_frag(void);
-float GPU_max_texture_anisotropy(void);
-int GPU_max_color_texture_samples(void);
-int GPU_max_cube_map_size(void);
-int GPU_max_ubo_binds(void);
-int GPU_max_ubo_size(void);
-void GPU_get_dfdy_factors(float fac[2]);
-bool GPU_arb_base_instance_is_supported(void);
-bool GPU_arb_texture_cube_map_array_is_supported(void);
+
+int GPU_texture_size_with_limit(int res);
+
bool GPU_mip_render_workaround(void);
bool GPU_depth_blitting_workaround(void);
-bool GPU_unused_fb_slot_workaround(void);
bool GPU_use_main_context_workaround(void);
-bool GPU_texture_copy_workaround(void);
bool GPU_crappy_amd_driver(void);
-int GPU_texture_size_with_limit(int res);
-
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
-void GPU_code_generate_glsl_lib(void);
-
bool GPU_stereo_quadbuffer_support(void);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index be7e604fb96..82f13424502 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -32,8 +32,6 @@
extern "C" {
#endif
-typedef struct GPUContext GPUContext;
-
typedef enum eGPUBackendType {
GPU_BACKEND_NONE = 0,
GPU_BACKEND_OPENGL,
@@ -42,6 +40,9 @@ typedef enum eGPUBackendType {
void GPU_backend_init(eGPUBackendType backend);
void GPU_backend_exit(void);
+/** Opaque type hiding blender::gpu::Context. */
+typedef struct GPUContext GPUContext;
+
GPUContext *GPU_context_create(void *ghost_window);
void GPU_context_discard(GPUContext *);
diff --git a/source/blender/gpu/GPU_drawlist.h b/source/blender/gpu/GPU_drawlist.h
index 27f70da8cf8..485b90f48d4 100644
--- a/source/blender/gpu/GPU_drawlist.h
+++ b/source/blender/gpu/GPU_drawlist.h
@@ -32,14 +32,15 @@ extern "C" {
struct GPUBatch;
-typedef void *GPUDrawList; /* Opaque pointer. */
+/** Opaque type hiding blender::gpu::DrawList. */
+typedef struct GPUDrawList GPUDrawList;
/* Create a list with at least length drawcalls. Length can affect performance. */
-GPUDrawList GPU_draw_list_create(int length);
-void GPU_draw_list_discard(GPUDrawList list);
+GPUDrawList *GPU_draw_list_create(int length);
+void GPU_draw_list_discard(GPUDrawList *list);
-void GPU_draw_list_append(GPUDrawList list, GPUBatch *batch, int i_first, int i_count);
-void GPU_draw_list_submit(GPUDrawList list);
+void GPU_draw_list_append(GPUDrawList *list, GPUBatch *batch, int i_first, int i_count);
+void GPU_draw_list_submit(GPUDrawList *list);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index f4599ac44bb..be55cd7af2d 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -54,10 +54,8 @@ typedef enum eGPUBackBuffer {
GPU_BACKBUFFER_RIGHT,
} eGPUBackBuffer;
-/** Opaque pointer hiding blender::gpu::FrameBuffer. */
-typedef struct GPUFrameBuffer {
- void *dummy;
-} GPUFrameBuffer;
+/** Opaque type hiding blender::gpu::FrameBuffer. */
+typedef struct GPUFrameBuffer GPUFrameBuffer;
typedef struct GPUOffScreen GPUOffScreen;
@@ -188,7 +186,8 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb,
void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]);
-void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data);
+void GPU_framebuffer_read_depth(
+ GPUFrameBuffer *fb, int x, int y, int w, int h, eGPUDataFormat format, void *data);
void GPU_framebuffer_read_color(GPUFrameBuffer *fb,
int x,
int y,
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
index 6057770d2d9..edb7c9fe5b5 100644
--- a/source/blender/gpu/GPU_immediate.h
+++ b/source/blender/gpu/GPU_immediate.h
@@ -145,12 +145,6 @@ void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int
void immUniformThemeColorBlend(int color_id1, int color_id2, float fac);
void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset);
-/* These are called by the system -- not part of drawing API. */
-void immInit(void);
-void immActivate(void);
-void immDeactivate(void);
-void immDestroy(void);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h
index df24e07caef..0c71dd539a6 100644
--- a/source/blender/gpu/GPU_index_buffer.h
+++ b/source/blender/gpu/GPU_index_buffer.h
@@ -31,11 +31,7 @@
extern "C" {
#endif
-/**
- * IMPORTANT: Do not allocate manually as the real struct is bigger (i.e: GLIndexBuf). This is only
- * the common and "public" part of the struct. Use the provided allocator.
- * TODO(fclem) Make the content of this struct hidden and expose getters/setters.
- **/
+/** Opaque type hiding blender::gpu::IndexBuf. */
typedef struct GPUIndexBuf GPUIndexBuf;
GPUIndexBuf *GPU_indexbuf_calloc(void);
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 869e8c32861..5e872001267 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -128,7 +128,6 @@ void GPU_write_mask(eGPUWriteMask mask);
void GPU_color_mask(bool r, bool g, bool b, bool a);
void GPU_depth_mask(bool depth);
bool GPU_depth_mask_get(void);
-void GPU_unpack_row_length_set(uint len);
void GPU_shadow_offset(bool enable);
void GPU_clip_distances(int distances_enabled);
bool GPU_mipmap_enabled(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index bae5bfbaae8..2ce2ba093cf 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -36,6 +36,8 @@ struct MovieClipUser;
struct PreviewImage;
struct GPUFrameBuffer;
+
+/** Opaque type hiding blender::gpu::Texture. */
typedef struct GPUTexture GPUTexture;
/* GPU Samplers state
@@ -228,14 +230,11 @@ void GPU_texture_update_sub(GPUTexture *tex,
int width,
int height,
int depth);
+void GPU_unpack_row_length_set(uint len);
void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
-void GPU_invalid_tex_init(void);
-void GPU_invalid_tex_bind(int mode);
-void GPU_invalid_tex_free(void);
-
void GPU_texture_free(GPUTexture *tex);
void GPU_texture_ref(GPUTexture *tex);
@@ -261,7 +260,6 @@ int GPU_texture_orig_width(const GPUTexture *tex);
int GPU_texture_orig_height(const GPUTexture *tex);
void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h);
eGPUTextureFormat GPU_texture_format(const GPUTexture *tex);
-int GPU_texture_samples(const GPUTexture *tex);
bool GPU_texture_array(const GPUTexture *tex);
bool GPU_texture_cube(const GPUTexture *tex);
bool GPU_texture_depth(const GPUTexture *tex);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index 605e2b14434..ebcaa80e6f6 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -36,10 +36,8 @@ extern "C" {
struct ListBase;
-/** Opaque pointer hiding blender::gpu::UniformBuf. */
-typedef struct GPUUniformBuf {
- void *dummy;
-} GPUUniformBuf;
+/** Opaque type hiding blender::gpu::UniformBuf. */
+typedef struct GPUUniformBuf GPUUniformBuf;
GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name);
GPUUniformBuf *GPU_uniformbuf_create_from_list(struct ListBase *inputs, const char *name);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 80f0501edc0..2af9929db35 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -61,6 +61,7 @@ typedef enum {
GPU_USAGE_DYNAMIC,
} GPUUsageType;
+/** Opaque type hiding blender::gpu::VertBuf. */
typedef struct GPUVertBuf GPUVertBuf;
GPUVertBuf *GPU_vertbuf_calloc(void);
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index d074350e8d0..04ec82a9213 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -25,15 +25,16 @@
#pragma once
-struct GPUContext;
-
namespace blender {
namespace gpu {
+class Context;
+
class Batch;
class DrawList;
class FrameBuffer;
class IndexBuf;
+class QueryPool;
class Shader;
class Texture;
class UniformBuf;
@@ -47,12 +48,13 @@ class GPUBackend {
virtual void samplers_update(void) = 0;
- virtual GPUContext *context_alloc(void *ghost_window) = 0;
+ virtual Context *context_alloc(void *ghost_window) = 0;
virtual Batch *batch_alloc(void) = 0;
virtual DrawList *drawlist_alloc(int list_length) = 0;
virtual FrameBuffer *framebuffer_alloc(const char *name) = 0;
virtual IndexBuf *indexbuf_alloc(void) = 0;
+ virtual QueryPool *querypool_alloc(void) = 0;
virtual Shader *shader_alloc(const char *name) = 0;
virtual Texture *texture_alloc(const char *name) = 0;
virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0;
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 34655c48ca4..de079a89de7 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -30,7 +30,6 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
-#include "GPU_extensions.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
@@ -259,7 +258,7 @@ void GPU_batch_draw_instanced(GPUBatch *batch, int i_count)
void GPU_batch_draw_advanced(
GPUBatch *gpu_batch, int v_first, int v_count, int i_first, int i_count)
{
- BLI_assert(GPU_context_active_get()->shader != NULL);
+ BLI_assert(Context::get()->shader != NULL);
Batch *batch = static_cast<Batch *>(gpu_batch);
if (v_count == 0) {
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
new file mode 100644
index 00000000000..a79ce27ba63
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -0,0 +1,127 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Wrap OpenGL features such as textures, shaders and GLSL
+ * with checks for drivers and GPU support.
+ */
+
+#include "DNA_userdef_types.h"
+
+#include "GPU_capabilities.h"
+
+#include "gpu_context_private.hh"
+
+#include "gpu_capabilities_private.hh"
+
+namespace blender::gpu {
+
+GPUCapabilities GCaps;
+
+}
+
+using namespace blender::gpu;
+
+/* -------------------------------------------------------------------- */
+/** \name Capabilities
+ * \{ */
+
+int GPU_max_texture_size(void)
+{
+ return GCaps.max_texture_size;
+}
+
+int GPU_texture_size_with_limit(int res)
+{
+ int size = GPU_max_texture_size();
+ int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
+ return min_ii(reslimit, res);
+}
+
+int GPU_max_texture_layers(void)
+{
+ return GCaps.max_texture_layers;
+}
+
+int GPU_max_textures_vert(void)
+{
+ return GCaps.max_textures_vert;
+}
+
+int GPU_max_textures_geom(void)
+{
+ return GCaps.max_textures_geom;
+}
+
+int GPU_max_textures_frag(void)
+{
+ return GCaps.max_textures_frag;
+}
+
+int GPU_max_textures(void)
+{
+ return GCaps.max_textures;
+}
+
+bool GPU_mip_render_workaround(void)
+{
+ return GCaps.mip_render_workaround;
+}
+
+bool GPU_depth_blitting_workaround(void)
+{
+ return GCaps.depth_blitting_workaround;
+}
+
+bool GPU_use_main_context_workaround(void)
+{
+ return GCaps.use_main_context_workaround;
+}
+
+bool GPU_crappy_amd_driver(void)
+{
+ /* Currently are the same drivers with the `unused_fb_slot` problem. */
+ return GCaps.broken_amd_driver;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Memory statistics
+ * \{ */
+
+bool GPU_mem_stats_supported(void)
+{
+ return GCaps.mem_stats_support;
+}
+
+void GPU_mem_stats_get(int *totalmem, int *freemem)
+{
+ Context::get()->memory_statistics_get(totalmem, freemem);
+}
+
+/* Return support for the active context + window. */
+bool GPU_stereo_quadbuffer_support(void)
+{
+ return Context::get()->front_right != nullptr;
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
new file mode 100644
index 00000000000..a51525fa932
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "GPU_platform.h"
+
+namespace blender::gpu {
+
+/**
+ * This includes both hardware capabilities & workarounds.
+ * Try to limit these to the implementation codebase (i.e.: gpu/opengl/).
+ * Only add workarounds here if they are common to all implementation or
+ * if you need access to it outside of the GPU module.
+ * Same goes for capabilities (i.e.: texture size)
+ **/
+struct GPUCapabilities {
+ int max_texture_size = 0;
+ int max_texture_layers = 0;
+ int max_textures = 0;
+ int max_textures_vert = 0;
+ int max_textures_geom = 0;
+ int max_textures_frag = 0;
+ bool mem_stats_support = false;
+ /* OpenGL related workarounds. */
+ bool mip_render_workaround = false;
+ bool depth_blitting_workaround = false;
+ bool use_main_context_workaround = false;
+ bool broken_amd_driver = false;
+ /* Vulkan related workarounds. */
+};
+
+extern GPUCapabilities GCaps;
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index d67ce0be310..f10fd8cd137 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -40,7 +40,7 @@
#include "BKE_material.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_uniform_buffer.h"
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 85e7dffe3e7..119c1ef9c55 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -54,20 +54,22 @@
using namespace blender::gpu;
-static thread_local GPUContext *active_ctx = NULL;
+static thread_local Context *active_ctx = NULL;
/* -------------------------------------------------------------------- */
-/** \name GPUContext methods
+/** \name gpu::Context methods
* \{ */
-GPUContext::GPUContext()
+namespace blender::gpu {
+
+Context::Context()
{
thread_ = pthread_self();
is_active_ = false;
matrix_state = GPU_matrix_state_create();
}
-GPUContext::~GPUContext()
+Context::~Context()
{
GPU_matrix_state_discard(matrix_state);
delete state_manager;
@@ -78,11 +80,18 @@ GPUContext::~GPUContext()
delete imm;
}
-bool GPUContext::is_active_on_thread(void)
+bool Context::is_active_on_thread(void)
{
return (this == active_ctx) && pthread_equal(pthread_self(), thread_);
}
+Context *Context::get(void)
+{
+ return active_ctx;
+}
+
+} // namespace blender::gpu
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -94,22 +103,25 @@ GPUContext *GPU_context_create(void *ghost_window)
GPU_backend_init(GPU_BACKEND_OPENGL);
}
- GPUContext *ctx = GPUBackend::get()->context_alloc(ghost_window);
+ Context *ctx = GPUBackend::get()->context_alloc(ghost_window);
- GPU_context_active_set(ctx);
- return ctx;
+ GPU_context_active_set(wrap(ctx));
+ return wrap(ctx);
}
/* to be called after GPU_context_active_set(ctx_to_destroy) */
-void GPU_context_discard(GPUContext *ctx)
+void GPU_context_discard(GPUContext *ctx_)
{
+ Context *ctx = unwrap(ctx_);
delete ctx;
active_ctx = NULL;
}
/* ctx can be NULL */
-void GPU_context_active_set(GPUContext *ctx)
+void GPU_context_active_set(GPUContext *ctx_)
{
+ Context *ctx = unwrap(ctx_);
+
if (active_ctx) {
active_ctx->deactivate();
}
@@ -123,65 +135,7 @@ void GPU_context_active_set(GPUContext *ctx)
GPUContext *GPU_context_active_get(void)
{
- return active_ctx;
-}
-
-GLuint GPU_vao_alloc(void)
-{
- GLuint new_vao_id = 0;
- glGenVertexArrays(1, &new_vao_id);
- return new_vao_id;
-}
-
-GLuint GPU_fbo_alloc(void)
-{
- GLuint new_fbo_id = 0;
- glGenFramebuffers(1, &new_fbo_id);
- return new_fbo_id;
-}
-
-GLuint GPU_buf_alloc(void)
-{
- GLuint new_buffer_id = 0;
- glGenBuffers(1, &new_buffer_id);
- return new_buffer_id;
-}
-
-GLuint GPU_tex_alloc(void)
-{
- GLuint new_texture_id = 0;
- glGenTextures(1, &new_texture_id);
- return new_texture_id;
-}
-
-void GPU_vao_free(GLuint vao_id, GPUContext *ctx)
-{
- static_cast<GLContext *>(ctx)->vao_free(vao_id);
-}
-
-void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx)
-{
- static_cast<GLContext *>(ctx)->fbo_free(fbo_id);
-}
-
-void GPU_buf_free(GLuint buf_id)
-{
- /* TODO avoid using backend */
- GPUBackend *backend = GPUBackend::get();
- static_cast<GLBackend *>(backend)->buf_free(buf_id);
-}
-
-void GPU_tex_free(GLuint tex_id)
-{
- /* TODO avoid using backend */
- GPUBackend *backend = GPUBackend::get();
- static_cast<GLBackend *>(backend)->tex_free(tex_id);
-}
-
-struct GPUMatrixState *gpu_context_active_matrix_state_get()
-{
- BLI_assert(active_ctx);
- return active_ctx->matrix_state;
+ return wrap(Context::get());
}
/* -------------------------------------------------------------------- */
@@ -231,6 +185,7 @@ void GPU_backend_exit(void)
/* TODO assert no resource left. Currently UI textures are still not freed in their context
* correctly. */
delete g_backend;
+ g_backend = NULL;
}
GPUBackend *GPUBackend::get(void)
diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh
index 20e57c405ba..bc07bea4bb1 100644
--- a/source/blender/gpu/intern/gpu_context_private.hh
+++ b/source/blender/gpu/intern/gpu_context_private.hh
@@ -34,22 +34,20 @@
#include "gpu_shader_private.hh"
#include "gpu_state_private.hh"
-#include <mutex>
#include <pthread.h>
-#include <string.h>
-#include <unordered_set>
-#include <vector>
struct GPUMatrixState;
-struct GPUContext {
+namespace blender::gpu {
+
+class Context {
public:
/** State management */
- blender::gpu::Shader *shader = NULL;
- blender::gpu::FrameBuffer *active_fb = NULL;
+ Shader *shader = NULL;
+ FrameBuffer *active_fb = NULL;
GPUMatrixState *matrix_state = NULL;
- blender::gpu::GPUStateManager *state_manager = NULL;
- blender::gpu::Immediate *imm = NULL;
+ GPUStateManager *state_manager = NULL;
+ Immediate *imm = NULL;
/**
* All 4 window frame-buffers.
@@ -58,10 +56,10 @@ struct GPUContext {
* Front frame-buffers contains (in principle, but not always) the last frame color.
* Default frame-buffer is back_left.
*/
- blender::gpu::FrameBuffer *back_left = NULL;
- blender::gpu::FrameBuffer *front_left = NULL;
- blender::gpu::FrameBuffer *back_right = NULL;
- blender::gpu::FrameBuffer *front_right = NULL;
+ FrameBuffer *back_left = NULL;
+ FrameBuffer *front_left = NULL;
+ FrameBuffer *back_right = NULL;
+ FrameBuffer *front_right = NULL;
protected:
/** Thread on which this context is active. */
@@ -71,31 +69,36 @@ struct GPUContext {
void *ghost_window_;
public:
- GPUContext();
- virtual ~GPUContext();
+ Context();
+ virtual ~Context();
+
+ static Context *get(void);
virtual void activate(void) = 0;
virtual void deactivate(void) = 0;
- bool is_active_on_thread(void);
-
- MEM_CXX_CLASS_ALLOC_FUNCS("GPUContext")
-};
-
-/* These require a OpenGL ctx bound. */
-GLuint GPU_buf_alloc(void);
-GLuint GPU_tex_alloc(void);
-GLuint GPU_vao_alloc(void);
-GLuint GPU_fbo_alloc(void);
+ /* Will push all pending commands to the GPU. */
+ virtual void flush(void) = 0;
+ /* Will wait until the GPU has finished executing all command. */
+ virtual void finish(void) = 0;
-/* These can be called any threads even without OpenGL ctx. */
-void GPU_buf_free(GLuint buf_id);
-void GPU_tex_free(GLuint tex_id);
-/* These two need the ctx the id was created with. */
-void GPU_vao_free(GLuint vao_id, GPUContext *ctx);
-void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx);
+ virtual void memory_statistics_get(int *total_mem, int *free_mem) = 0;
-void gpu_context_active_framebuffer_set(GPUContext *ctx, struct GPUFrameBuffer *fb);
-struct GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx);
+ bool is_active_on_thread(void);
+};
-struct GPUMatrixState *gpu_context_active_matrix_state_get(void);
+/* Syntacting suggar. */
+static inline GPUContext *wrap(Context *ctx)
+{
+ return reinterpret_cast<GPUContext *>(ctx);
+}
+static inline Context *unwrap(GPUContext *ctx)
+{
+ return reinterpret_cast<Context *>(ctx);
+}
+static inline const Context *unwrap(const GPUContext *ctx)
+{
+ return reinterpret_cast<const Context *>(ctx);
+}
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc
index 7b807a2fa80..ecea4f7c5e4 100644
--- a/source/blender/gpu/intern/gpu_drawlist.cc
+++ b/source/blender/gpu/intern/gpu_drawlist.cc
@@ -34,26 +34,26 @@
using namespace blender::gpu;
-GPUDrawList GPU_draw_list_create(int list_length)
+GPUDrawList *GPU_draw_list_create(int list_length)
{
DrawList *list_ptr = GPUBackend::get()->drawlist_alloc(list_length);
- return reinterpret_cast<DrawList *>(list_ptr);
+ return wrap(list_ptr);
}
-void GPU_draw_list_discard(GPUDrawList list)
+void GPU_draw_list_discard(GPUDrawList *list)
{
- DrawList *list_ptr = reinterpret_cast<DrawList *>(list);
+ DrawList *list_ptr = unwrap(list);
delete list_ptr;
}
-void GPU_draw_list_append(GPUDrawList list, GPUBatch *batch, int i_first, int i_count)
+void GPU_draw_list_append(GPUDrawList *list, GPUBatch *batch, int i_first, int i_count)
{
- DrawList *list_ptr = reinterpret_cast<DrawList *>(list);
+ DrawList *list_ptr = unwrap(list);
list_ptr->append(batch, i_first, i_count);
}
-void GPU_draw_list_submit(GPUDrawList list)
+void GPU_draw_list_submit(GPUDrawList *list)
{
- DrawList *list_ptr = reinterpret_cast<DrawList *>(list);
+ DrawList *list_ptr = unwrap(list);
list_ptr->submit();
}
diff --git a/source/blender/gpu/intern/gpu_drawlist_private.hh b/source/blender/gpu/intern/gpu_drawlist_private.hh
index ddb09fb0c89..fd223c3f255 100644
--- a/source/blender/gpu/intern/gpu_drawlist_private.hh
+++ b/source/blender/gpu/intern/gpu_drawlist_private.hh
@@ -25,6 +25,8 @@
#include "MEM_guardedalloc.h"
+#include "GPU_drawlist.h"
+
namespace blender {
namespace gpu {
@@ -40,5 +42,19 @@ class DrawList {
virtual void submit() = 0;
};
+/* Syntacting suggar. */
+static inline GPUDrawList *wrap(DrawList *vert)
+{
+ return reinterpret_cast<GPUDrawList *>(vert);
+}
+static inline DrawList *unwrap(GPUDrawList *vert)
+{
+ return reinterpret_cast<DrawList *>(vert);
+}
+static inline const DrawList *unwrap(const GPUDrawList *vert)
+{
+ return reinterpret_cast<const DrawList *>(vert);
+}
+
} // namespace gpu
} // namespace blender
diff --git a/source/blender/gpu/intern/gpu_extensions.cc b/source/blender/gpu/intern/gpu_extensions.cc
deleted file mode 100644
index ac7748e6430..00000000000
--- a/source/blender/gpu/intern/gpu_extensions.cc
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup gpu
- *
- * Wrap OpenGL features such as textures, shaders and GLSL
- * with checks for drivers and GPU support.
- */
-
-#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_global.h"
-#include "MEM_guardedalloc.h"
-
-#include "DNA_userdef_types.h"
-
-#include "GPU_extensions.h"
-#include "GPU_framebuffer.h"
-#include "GPU_glew.h"
-#include "GPU_platform.h"
-#include "GPU_texture.h"
-
-#include "intern/gpu_private.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
-/* Extensions support */
-
-/* -- extension: version of GL that absorbs it
- * EXT_gpu_shader4: 3.0
- * ARB_framebuffer object: 3.0
- * EXT_framebuffer_multisample_blit_scaled: ???
- * ARB_draw_instanced: 3.1
- * ARB_texture_multisample: 3.2
- * ARB_texture_query_lod: 4.0
- */
-
-static struct GPUGlobal {
- GLint maxtexsize;
- GLint maxtex3dsize;
- GLint maxtexlayers;
- GLint maxcubemapsize;
- GLint maxtextures;
- GLint maxtexturesfrag;
- GLint maxtexturesgeom;
- GLint maxtexturesvert;
- GLint maxubosize;
- GLint maxubobinds;
- int samples_color_texture_max;
- /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
- * calculate dfdy in shader differently when drawing to an off-screen buffer. First
- * number is factor on screen and second is off-screen */
- float dfdyfactors[2];
- /* Some Intel drivers have limited support for `GLEW_ARB_base_instance` so in
- * these cases it is best to indicate that it is not supported. See T67951 */
- bool glew_arb_base_instance_is_supported;
- /* Cubemap Array support. */
- bool glew_arb_texture_cube_map_array_is_supported;
- /* Some Intel drivers have issues with using mips as framebuffer targets if
- * GL_TEXTURE_MAX_LEVEL is higher than the target mip.
- * We need a workaround in this cases. */
- bool mip_render_workaround;
- /* There is an issue with the #glBlitFramebuffer on MacOS with radeon pro graphics.
- * Blitting depth with#GL_DEPTH24_STENCIL8 is buggy so the workaround is to use
- * #GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will
- * still be broken. */
- bool depth_blitting_workaround;
- /* Crappy driver don't know how to map framebuffer slot to output vars...
- * We need to have no "holes" in the output buffer slots. */
- bool unused_fb_slot_workaround;
- bool broken_amd_driver;
- /* Some crappy Intel drivers don't work well with shaders created in different
- * rendering contexts. */
- bool use_main_context_workaround;
- /* Intel drivers exhibit artifacts when using #glCopyImageSubData & workbench anti-aliasing.
- * (see T76273) */
- bool texture_copy_workaround;
-} GG = {1, 0};
-
-static void gpu_detect_mip_render_workaround(void)
-{
- int cube_size = 2;
- float *source_pix = (float *)MEM_callocN(sizeof(float[4][6]) * cube_size * cube_size, __func__);
- float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f};
-
- GPUTexture *tex = GPU_texture_create_cube(__func__, cube_size, 2, GPU_RGBA16F, source_pix);
- MEM_freeN(source_pix);
-
- GPU_texture_bind(tex, 0);
- GPU_texture_generate_mipmap(tex);
- glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, 0);
- GPU_texture_unbind(tex);
-
- GPUFrameBuffer *fb = GPU_framebuffer_create(__func__);
- GPU_framebuffer_texture_attach(fb, tex, 0, 1);
- GPU_framebuffer_bind(fb);
- GPU_framebuffer_clear_color(fb, clear_color);
- GPU_framebuffer_restore();
- GPU_framebuffer_free(fb);
-
- float *data = (float *)GPU_texture_read(tex, GPU_DATA_FLOAT, 1);
- GG.mip_render_workaround = !equals_v4v4(clear_color, data);
-
- MEM_freeN(data);
- GPU_texture_free(tex);
-}
-
-/* GPU Extensions */
-
-int GPU_max_texture_size(void)
-{
- return GG.maxtexsize;
-}
-
-int GPU_max_texture_3d_size(void)
-{
- return GG.maxtex3dsize;
-}
-
-int GPU_max_texture_layers(void)
-{
- return GG.maxtexlayers;
-}
-
-int GPU_max_textures(void)
-{
- return GG.maxtextures;
-}
-
-int GPU_max_textures_frag(void)
-{
- return GG.maxtexturesfrag;
-}
-
-int GPU_max_textures_geom(void)
-{
- return GG.maxtexturesgeom;
-}
-
-int GPU_max_textures_vert(void)
-{
- return GG.maxtexturesvert;
-}
-
-int GPU_max_color_texture_samples(void)
-{
- return GG.samples_color_texture_max;
-}
-
-int GPU_max_cube_map_size(void)
-{
- return GG.maxcubemapsize;
-}
-
-int GPU_max_ubo_binds(void)
-{
- return GG.maxubobinds;
-}
-
-int GPU_max_ubo_size(void)
-{
- return GG.maxubosize;
-}
-
-void GPU_get_dfdy_factors(float fac[2])
-{
- copy_v2_v2(fac, GG.dfdyfactors);
-}
-
-bool GPU_arb_base_instance_is_supported(void)
-{
- return GG.glew_arb_base_instance_is_supported;
-}
-
-bool GPU_arb_texture_cube_map_array_is_supported(void)
-{
- return GG.glew_arb_texture_cube_map_array_is_supported;
-}
-
-bool GPU_mip_render_workaround(void)
-{
- return GG.mip_render_workaround;
-}
-
-bool GPU_depth_blitting_workaround(void)
-{
- return GG.depth_blitting_workaround;
-}
-
-bool GPU_unused_fb_slot_workaround(void)
-{
- return GG.unused_fb_slot_workaround;
-}
-
-bool GPU_use_main_context_workaround(void)
-{
- return GG.use_main_context_workaround;
-}
-
-bool GPU_texture_copy_workaround(void)
-{
- return GG.texture_copy_workaround;
-}
-
-bool GPU_crappy_amd_driver(void)
-{
- /* Currently are the same drivers with the `unused_fb_slot` problem. */
- return GG.broken_amd_driver;
-}
-
-int GPU_texture_size_with_limit(int res)
-{
- int size = GPU_max_texture_size();
- int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
- return min_ii(reslimit, res);
-}
-
-void gpu_extensions_init(void)
-{
- /* during 2.8 development each platform has its own OpenGL minimum requirements
- * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions
- * see developer.blender.org/T49012 for details
- */
- BLI_assert(GLEW_VERSION_3_3);
-
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtexturesfrag);
- glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GG.maxtexturesvert);
- glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GG.maxtexturesgeom);
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
-
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
- glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GG.maxtex3dsize);
- glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GG.maxtexlayers);
- glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);
-
- glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds);
- glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize);
-
- glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
-
- const char *vendor = (const char *)glGetString(GL_VENDOR);
- const char *renderer = (const char *)glGetString(GL_RENDERER);
- const char *version = (const char *)glGetString(GL_VERSION);
-
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) {
- if (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") ||
- strstr(version, "4.5.13422")) {
- /* The renderers include:
- * Mobility Radeon HD 5000;
- * Radeon HD 7500M;
- * Radeon HD 7570M;
- * Radeon HD 7600M;
- * And many others... */
-
- GG.unused_fb_slot_workaround = true;
- GG.broken_amd_driver = true;
- }
- }
-
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
- strstr(renderer, "AMD VERDE")) {
- /* We have issues with this specific renderer. (see T74024) */
- GG.unused_fb_slot_workaround = true;
- GG.broken_amd_driver = true;
- }
-
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
- strstr(version, "Mesa 19.3.4")) {
- /* Fix slowdown on this particular driver. (see T77641) */
- GG.broken_amd_driver = true;
- }
-
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) {
- if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") ||
- strstr(renderer, "AMD Radeon RX")) {
- GG.depth_blitting_workaround = true;
- }
- }
-
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) {
- /* Limit this fix to older hardware with GL < 4.5. This means Broadwell GPUs are
- * covered since they only support GL 4.4 on windows.
- * This fixes some issues with workbench anti-aliasing on Win + Intel GPU. (see T76273) */
- if (!GLEW_VERSION_4_5) {
- GG.texture_copy_workaround = true;
- }
- }
-
- /* Limit support for GLEW_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800
- * (TeraScale) report that they support GLEW_ARB_base_instance, but the driver does not support
- * GLEW_ARB_draw_indirect as it has an OpenGL3 context what also matches the minimum needed
- * requirements.
- *
- * We use it as a target for glMapBuffer(Range) what is part of the OpenGL 4 API. So better
- * disable it when we don't have an OpenGL4 context (See T77657) */
- GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance && GLEW_VERSION_4_0;
- GG.glew_arb_texture_cube_map_array_is_supported = GLEW_ARB_texture_cube_map_array;
- gpu_detect_mip_render_workaround();
-
- if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) {
- printf("\n");
- printf("GPU: Bypassing workaround detection.\n");
- printf("GPU: OpenGL identification strings\n");
- printf("GPU: vendor: %s\n", vendor);
- printf("GPU: renderer: %s\n", renderer);
- printf("GPU: version: %s\n\n", version);
- GG.mip_render_workaround = true;
- GG.depth_blitting_workaround = true;
- GG.unused_fb_slot_workaround = true;
- GG.texture_copy_workaround = true;
- }
-
- /* Special fix for theses specific GPUs.
- * Without this workaround, blender crashes on startup. (see T72098) */
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
- (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) {
- GG.mip_render_workaround = true;
- }
-
- /* Intel Ivy Bridge GPU's seems to have buggy cube-map array support. (see T75943) */
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
- (strstr(renderer, "HD Graphics 4000") || strstr(renderer, "HD Graphics 4400") ||
- strstr(renderer, "HD Graphics 2500"))) {
- GG.glew_arb_texture_cube_map_array_is_supported = false;
- }
-
- /* df/dy calculation factors, those are dependent on driver */
- GG.dfdyfactors[0] = 1.0;
- GG.dfdyfactors[1] = 1.0;
-
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) &&
- strstr(version, "3.3.10750")) {
- GG.dfdyfactors[0] = 1.0;
- GG.dfdyfactors[1] = -1.0;
- }
- else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
- if (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
- strstr(version, "4.0.0 - Build 9.18.10.3186") ||
- strstr(version, "4.0.0 - Build 9.18.10.3165") ||
- strstr(version, "3.1.0 - Build 9.17.10.3347") ||
- strstr(version, "3.1.0 - Build 9.17.10.4101") ||
- strstr(version, "3.3.0 - Build 8.15.10.2618")) {
- GG.dfdyfactors[0] = -1.0;
- GG.dfdyfactors[1] = 1.0;
- }
-
- if (strstr(version, "Build 10.18.10.3") || strstr(version, "Build 10.18.10.4") ||
- strstr(version, "Build 10.18.10.5") || strstr(version, "Build 10.18.14.4") ||
- strstr(version, "Build 10.18.14.5")) {
- /* Maybe not all of these drivers have problems with `GLEW_ARB_base_instance`.
- * But it's hard to test each case. */
- GG.glew_arb_base_instance_is_supported = false;
- GG.use_main_context_workaround = true;
- }
-
- if (strstr(version, "Build 20.19.15.4285")) {
- /* Somehow fixes armature display issues (see T69743). */
- GG.use_main_context_workaround = true;
- }
- }
- else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
- (strstr(version, "Mesa 18.") || strstr(version, "Mesa 19.0") ||
- strstr(version, "Mesa 19.1") || strstr(version, "Mesa 19.2"))) {
- /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the
- * Mesa driver */
- GG.unused_fb_slot_workaround = true;
- }
-
- GPU_invalid_tex_init();
-}
-
-void gpu_extensions_exit(void)
-{
- GPU_invalid_tex_free();
-}
-
-bool GPU_mem_stats_supported(void)
-{
-#ifndef GPU_STANDALONE
- return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo);
-#else
- return false;
-#endif
-}
-
-void GPU_mem_stats_get(int *totalmem, int *freemem)
-{
- /* TODO(merwin): use Apple's platform API to get this info */
-
- if (GLEW_NVX_gpu_memory_info) {
- /* returned value in Kb */
- glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
-
- glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem);
- }
- else if (GLEW_ATI_meminfo) {
- int stats[4];
-
- glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
- *freemem = stats[0];
- *totalmem = 0;
- }
- else {
- *totalmem = 0;
- *freemem = 0;
- }
-}
-
-/* Return support for the active context + window. */
-bool GPU_stereo_quadbuffer_support(void)
-{
- GLboolean stereo = GL_FALSE;
- glGetBooleanv(GL_STEREO, &stereo);
- return stereo == GL_TRUE;
-}
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 44994c2cabf..88779dead28 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -28,7 +28,7 @@
#include "BLI_utildefines.h"
#include "GPU_batch.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -194,21 +194,20 @@ GPUFrameBuffer *GPU_framebuffer_create(const char *name)
{
/* We generate the FB object later at first use in order to
* create the frame-buffer in the right opengl context. */
- return (GPUFrameBuffer *)GPUBackend::get()->framebuffer_alloc(name);
+ return wrap(GPUBackend::get()->framebuffer_alloc(name));
}
void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb)
{
- delete reinterpret_cast<FrameBuffer *>(gpu_fb);
+ delete unwrap(gpu_fb);
}
/* ---------- Binding ----------- */
void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
const bool enable_srgb = true;
- fb->bind(enable_srgb);
+ unwrap(gpu_fb)->bind(enable_srgb);
}
/**
@@ -216,9 +215,8 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
*/
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
const bool enable_srgb = false;
- fb->bind(enable_srgb);
+ unwrap(gpu_fb)->bind(enable_srgb);
}
/**
@@ -226,7 +224,7 @@ void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
*/
void GPU_backbuffer_bind(eGPUBackBuffer buffer)
{
- GPUContext *ctx = GPU_context_active_get();
+ Context *ctx = Context::get();
if (buffer == GPU_BACKBUFFER_LEFT) {
ctx->back_left->bind(false);
@@ -238,20 +236,20 @@ void GPU_backbuffer_bind(eGPUBackBuffer buffer)
void GPU_framebuffer_restore(void)
{
- GPU_context_active_get()->back_left->bind(false);
+ Context::get()->back_left->bind(false);
}
GPUFrameBuffer *GPU_framebuffer_active_get(void)
{
- GPUContext *ctx = GPU_context_active_get();
- return reinterpret_cast<GPUFrameBuffer *>(ctx ? ctx->active_fb : NULL);
+ Context *ctx = Context::get();
+ return wrap(ctx ? ctx->active_fb : NULL);
}
/* Returns the default frame-buffer. Will always exists even if it's just a dummy. */
GPUFrameBuffer *GPU_framebuffer_back_get(void)
{
- GPUContext *ctx = GPU_context_active_get();
- return reinterpret_cast<GPUFrameBuffer *>(ctx ? ctx->back_left : NULL);
+ Context *ctx = Context::get();
+ return wrap(ctx ? ctx->back_left : NULL);
}
bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
@@ -263,14 +261,14 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
bool GPU_framebuffer_check_valid(GPUFrameBuffer *gpu_fb, char err_out[256])
{
- return reinterpret_cast<FrameBuffer *>(gpu_fb)->check(err_out);
+ return unwrap(gpu_fb)->check(err_out);
}
void GPU_framebuffer_texture_attach_ex(GPUFrameBuffer *gpu_fb, GPUAttachment attachment, int slot)
{
Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
GPUAttachmentType type = tex->attachment_type(slot);
- reinterpret_cast<FrameBuffer *>(gpu_fb)->attachment_set(type, attachment);
+ unwrap(gpu_fb)->attachment_set(type, attachment);
}
void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
@@ -293,10 +291,9 @@ void GPU_framebuffer_texture_cubeface_attach(
GPU_framebuffer_texture_attach_ex(fb, attachment, slot);
}
-void GPU_framebuffer_texture_detach(GPUFrameBuffer *gpu_fb, GPUTexture *tex)
+void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- reinterpret_cast<Texture *>(tex)->detach_from(fb);
+ unwrap(tex)->detach_from(unwrap(fb));
}
/**
@@ -309,7 +306,7 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
const GPUAttachment *config,
int config_len)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
+ FrameBuffer *fb = unwrap(gpu_fb);
const GPUAttachment &depth_attachment = config[0];
Span<GPUAttachment> color_attachments(config + 1, config_len - 1);
@@ -346,12 +343,12 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
{
int viewport_rect[4] = {x, y, width, height};
- reinterpret_cast<FrameBuffer *>(gpu_fb)->viewport_set(viewport_rect);
+ unwrap(gpu_fb)->viewport_set(viewport_rect);
}
void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
{
- reinterpret_cast<FrameBuffer *>(gpu_fb)->viewport_get(r_viewport);
+ unwrap(gpu_fb)->viewport_get(r_viewport);
}
/**
@@ -359,7 +356,7 @@ void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
*/
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb)
{
- reinterpret_cast<FrameBuffer *>(gpu_fb)->viewport_reset();
+ unwrap(gpu_fb)->viewport_reset();
}
/* ---------- Framebuffer Operations ----------- */
@@ -370,7 +367,7 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
float clear_depth,
uint clear_stencil)
{
- reinterpret_cast<FrameBuffer *>(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
+ unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
}
/**
@@ -378,25 +375,26 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
*/
void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
{
- reinterpret_cast<FrameBuffer *>(gpu_fb)->clear_multi(clear_cols);
+ unwrap(gpu_fb)->clear_multi(clear_cols);
}
void GPU_clear_color(float red, float green, float blue, float alpha)
{
float clear_col[4] = {red, green, blue, alpha};
- GPU_context_active_get()->active_fb->clear(GPU_COLOR_BIT, clear_col, 0.0f, 0x0);
+ Context::get()->active_fb->clear(GPU_COLOR_BIT, clear_col, 0.0f, 0x0);
}
void GPU_clear_depth(float depth)
{
float clear_col[4] = {0};
- GPU_context_active_get()->active_fb->clear(GPU_DEPTH_BIT, clear_col, depth, 0x0);
+ Context::get()->active_fb->clear(GPU_DEPTH_BIT, clear_col, depth, 0x0);
}
-void GPU_framebuffer_read_depth(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, float *data)
+void GPU_framebuffer_read_depth(
+ GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, eGPUDataFormat format, void *data)
{
int rect[4] = {x, y, w, h};
- reinterpret_cast<FrameBuffer *>(gpu_fb)->read(GPU_DEPTH_BIT, GPU_DATA_FLOAT, rect, 1, 1, data);
+ unwrap(gpu_fb)->read(GPU_DEPTH_BIT, format, rect, 1, 1, data);
}
void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb,
@@ -410,7 +408,7 @@ void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb,
void *data)
{
int rect[4] = {x, y, w, h};
- reinterpret_cast<FrameBuffer *>(gpu_fb)->read(GPU_COLOR_BIT, format, rect, channels, slot, data);
+ unwrap(gpu_fb)->read(GPU_COLOR_BIT, format, rect, channels, slot, data);
}
/* TODO(fclem) rename to read_color. */
@@ -418,7 +416,7 @@ void GPU_frontbuffer_read_pixels(
int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
{
int rect[4] = {x, y, w, h};
- GPU_context_active_get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
+ Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
}
/* read_slot and write_slot are only used for color buffers. */
@@ -429,11 +427,11 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
int write_slot,
eGPUFrameBufferBits blit_buffers)
{
- FrameBuffer *fb_read = reinterpret_cast<FrameBuffer *>(gpufb_read);
- FrameBuffer *fb_write = reinterpret_cast<FrameBuffer *>(gpufb_write);
+ FrameBuffer *fb_read = unwrap(gpufb_read);
+ FrameBuffer *fb_write = unwrap(gpufb_write);
BLI_assert(blit_buffers != 0);
- FrameBuffer *prev_fb = GPU_context_active_get()->active_fb;
+ FrameBuffer *prev_fb = Context::get()->active_fb;
#ifndef NDEBUG
GPUTexture *read_tex, *write_tex;
@@ -454,11 +452,6 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex));
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
}
- if (GPU_texture_samples(write_tex) != 0 || GPU_texture_samples(read_tex) != 0) {
- /* Can only blit multisample textures to another texture of the same size. */
- BLI_assert((GPU_texture_width(write_tex) == GPU_texture_width(read_tex)) &&
- (GPU_texture_height(write_tex) == GPU_texture_height(read_tex)));
- }
#endif
fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0);
@@ -477,7 +470,7 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
void (*callback)(void *userData, int level),
void *userData)
{
- reinterpret_cast<FrameBuffer *>(gpu_fb)->recursive_downsample(max_lvl, callback, userData);
+ unwrap(gpu_fb)->recursive_downsample(max_lvl, callback, userData);
}
/** \} */
@@ -516,7 +509,7 @@ static GPUFrameBuffer *gpuPopFrameBuffer(void)
struct GPUOffScreen {
struct {
- GPUContext *ctx;
+ Context *ctx;
GPUFrameBuffer *fb;
} framebuffers[MAX_CTX_FB_LEN];
@@ -529,7 +522,7 @@ struct GPUOffScreen {
*/
static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
{
- GPUContext *ctx = GPU_context_active_get();
+ Context *ctx = Context::get();
BLI_assert(ctx);
for (int i = 0; i < MAX_CTX_FB_LEN; i++) {
@@ -620,9 +613,9 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
{
if (save) {
GPUFrameBuffer *fb = GPU_framebuffer_active_get();
- gpuPushFrameBuffer(reinterpret_cast<GPUFrameBuffer *>(fb));
+ gpuPushFrameBuffer(fb);
}
- reinterpret_cast<FrameBuffer *>(gpu_offscreen_fb_get(ofs))->bind(false);
+ unwrap(gpu_offscreen_fb_get(ofs))->bind(false);
}
void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
@@ -642,8 +635,8 @@ void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y)
{
- GPUContext *ctx = GPU_context_active_get();
- FrameBuffer *ofs_fb = reinterpret_cast<FrameBuffer *>(gpu_offscreen_fb_get(ofs));
+ Context *ctx = Context::get();
+ FrameBuffer *ofs_fb = unwrap(gpu_offscreen_fb_get(ofs));
ofs_fb->blit_to(GPU_COLOR_BIT, 0, ctx->active_fb, 0, x, y);
}
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index 81507f4111a..da44773039b 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -209,6 +209,20 @@ class FrameBuffer {
};
};
+/* Syntacting suggar. */
+static inline GPUFrameBuffer *wrap(FrameBuffer *vert)
+{
+ return reinterpret_cast<GPUFrameBuffer *>(vert);
+}
+static inline FrameBuffer *unwrap(GPUFrameBuffer *vert)
+{
+ return reinterpret_cast<FrameBuffer *>(vert);
+}
+static inline const FrameBuffer *unwrap(const GPUFrameBuffer *vert)
+{
+ return reinterpret_cast<const FrameBuffer *>(vert);
+}
+
#undef DEBUG_NAME_LEN
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index dd3e5bea604..0a488c0dfc0 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -39,16 +39,11 @@
using namespace blender::gpu;
-static Immediate *imm = NULL;
-
-void immInit(void)
-{
- /* TODO Remove */
-}
+static thread_local Immediate *imm = NULL;
void immActivate(void)
{
- imm = GPU_context_active_get()->imm;
+ imm = Context::get()->imm;
}
void immDeactivate(void)
@@ -56,11 +51,6 @@ void immDeactivate(void)
imm = NULL;
}
-void immDestroy(void)
-{
- /* TODO Remove */
-}
-
GPUVertFormat *immVertexFormat(void)
{
GPU_vertformat_clear(&imm->vertex_format);
diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh
index aa99fb9a438..38db8131942 100644
--- a/source/blender/gpu/intern/gpu_immediate_private.hh
+++ b/source/blender/gpu/intern/gpu_immediate_private.hh
@@ -63,4 +63,7 @@ class Immediate {
virtual void end(void) = 0;
};
-} // namespace blender::gpu \ No newline at end of file
+} // namespace blender::gpu
+
+void immActivate(void);
+void immDeactivate(void); \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 4cb43db9bce..0eb2fe57c28 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -48,18 +48,12 @@ void GPU_init(void)
}
initialized = true;
- gpu_platform_init();
- gpu_extensions_init(); /* must come first */
gpu_codegen_init();
gpu_material_library_init();
gpu_batch_init();
- if (!G.background) {
- immInit();
- }
-
#ifndef GPU_STANDALONE
gpu_pbvh_init();
#endif
@@ -71,18 +65,11 @@ void GPU_exit(void)
gpu_pbvh_exit();
#endif
- if (!G.background) {
- immDestroy();
- }
-
gpu_batch_exit();
gpu_material_library_exit();
gpu_codegen_exit();
- gpu_extensions_exit();
- gpu_platform_exit(); /* must come last */
-
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index cdb6d303588..0274966d4b9 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -35,6 +35,8 @@
#include "MEM_guardedalloc.h"
+using namespace blender::gpu;
+
#define MATRIX_STACK_DEPTH 32
typedef float Mat4[4][4];
@@ -59,10 +61,10 @@ typedef struct GPUMatrixState {
*/
} GPUMatrixState;
-#define ModelViewStack gpu_context_active_matrix_state_get()->model_view_stack
+#define ModelViewStack Context::get()->matrix_state->model_view_stack
#define ModelView ModelViewStack.stack[ModelViewStack.top]
-#define ProjectionStack gpu_context_active_matrix_state_get()->projection_stack
+#define ProjectionStack Context::get()->matrix_state->projection_stack
#define Projection ProjectionStack.stack[ProjectionStack.top]
GPUMatrixState *GPU_matrix_state_create(void)
@@ -93,13 +95,13 @@ void GPU_matrix_state_discard(GPUMatrixState *state)
static void gpu_matrix_state_active_set_dirty(bool value)
{
- GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ GPUMatrixState *state = Context::get()->matrix_state;
state->dirty = value;
}
void GPU_matrix_reset(void)
{
- GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ GPUMatrixState *state = Context::get()->matrix_state;
state->model_view_stack.top = 0;
state->projection_stack.top = 0;
unit_m4(ModelView);
@@ -686,7 +688,7 @@ void GPU_matrix_bind(GPUShader *shader)
bool GPU_matrix_dirty_get(void)
{
- GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ GPUMatrixState *state = Context::get()->matrix_state;
return state->dirty;
}
@@ -699,13 +701,13 @@ BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mis
int GPU_matrix_stack_level_get_model_view(void)
{
- GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->model_view_stack.top;
}
int GPU_matrix_stack_level_get_projection(void)
{
- GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->projection_stack.top;
}
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index 5cabde61bc3..e4db8c93f1d 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -23,75 +23,31 @@
* Wrap OpenGL features such as textures, shaders and GLSL
* with checks for drivers and GPU support.
*/
-#include "GPU_platform.h"
-#include "GPU_glew.h"
-#include "gpu_private.h"
-#include <string.h>
+#include "MEM_guardedalloc.h"
#include "BLI_dynstr.h"
#include "BLI_string.h"
-#include "MEM_guardedalloc.h"
+#include "GPU_platform.h"
-static struct GPUPlatformGlobal {
- bool initialized;
- eGPUDeviceType device;
- eGPUOSType os;
- eGPUDriverType driver;
- eGPUSupportLevel support_level;
- char *support_key;
- char *gpu_name;
-} GPG = {false};
-
-/* Remove this? */
-#if 0
-typedef struct GPUPlatformSupportTest {
- eGPUSupportLevel support_level;
- eGPUDeviceType device;
- eGPUOSType os;
- eGPUDriverType driver;
- const char *vendor;
- const char *renderer;
- const char *version;
-} GPUPlatformSupportTest;
-#endif
+#include "gpu_platform_private.hh"
-eGPUSupportLevel GPU_platform_support_level(void)
-{
- return GPG.support_level;
-}
+/* -------------------------------------------------------------------- */
+/** \name GPUPlatformGlobal
+ * \{ */
-const char *GPU_platform_support_level_key(void)
-{
- return GPG.support_key;
-}
+namespace blender::gpu {
-const char *GPU_platform_gpu_name(void)
-{
- return GPG.gpu_name;
-}
+GPUPlatformGlobal GPG;
-/* GPU Types */
-bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
-{
- return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver);
-}
-
-static char *gpu_platform_create_key(eGPUSupportLevel support_level,
- const char *vendor,
- const char *renderer,
- const char *version)
+void GPUPlatformGlobal::create_key(eGPUSupportLevel support_level,
+ const char *vendor,
+ const char *renderer,
+ const char *version)
{
DynStr *ds = BLI_dynstr_new();
- BLI_dynstr_append(ds, "{");
- BLI_dynstr_append(ds, vendor);
- BLI_dynstr_append(ds, "/");
- BLI_dynstr_append(ds, renderer);
- BLI_dynstr_append(ds, "/");
- BLI_dynstr_append(ds, version);
- BLI_dynstr_append(ds, "}");
- BLI_dynstr_append(ds, "=");
+ BLI_dynstr_appendf(ds, "{%s/%s/%s}=", vendor, renderer, version);
if (support_level == GPU_SUPPORT_LEVEL_SUPPORTED) {
BLI_dynstr_append(ds, "SUPPORTED");
}
@@ -102,132 +58,61 @@ static char *gpu_platform_create_key(eGPUSupportLevel support_level,
BLI_dynstr_append(ds, "UNSUPPORTED");
}
- char *support_key = BLI_dynstr_get_cstring(ds);
+ support_key = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
BLI_str_replace_char(support_key, '\n', ' ');
BLI_str_replace_char(support_key, '\r', ' ');
- return support_key;
}
-static char *gpu_platform_create_gpu_name(const char *vendor,
- const char *renderer,
- const char *version)
+void GPUPlatformGlobal::create_gpu_name(const char *vendor,
+ const char *renderer,
+ const char *version)
{
DynStr *ds = BLI_dynstr_new();
- BLI_dynstr_append(ds, vendor);
- BLI_dynstr_append(ds, " ");
- BLI_dynstr_append(ds, renderer);
- BLI_dynstr_append(ds, " ");
- BLI_dynstr_append(ds, version);
+ BLI_dynstr_appendf(ds, "%s %s %s", vendor, renderer, version);
- char *gpu_name = BLI_dynstr_get_cstring(ds);
+ gpu_name = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
BLI_str_replace_char(gpu_name, '\n', ' ');
BLI_str_replace_char(gpu_name, '\r', ' ');
- return gpu_name;
}
-void gpu_platform_init(void)
+void GPUPlatformGlobal::clear(void)
{
- if (GPG.initialized) {
- return;
- }
+ MEM_SAFE_FREE(GPG.support_key);
+ MEM_SAFE_FREE(GPG.gpu_name);
+ initialized = false;
+}
-#ifdef _WIN32
- GPG.os = GPU_OS_WIN;
-#elif defined(__APPLE__)
- GPG.os = GPU_OS_MAC;
-#else
- GPG.os = GPU_OS_UNIX;
-#endif
-
- const char *vendor = (const char *)glGetString(GL_VENDOR);
- const char *renderer = (const char *)glGetString(GL_RENDERER);
- const char *version = (const char *)glGetString(GL_VERSION);
-
- if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
- GPG.device = GPU_DEVICE_ATI;
- GPG.driver = GPU_DRIVER_OFFICIAL;
- }
- else if (strstr(vendor, "NVIDIA")) {
- GPG.device = GPU_DEVICE_NVIDIA;
- GPG.driver = GPU_DRIVER_OFFICIAL;
- }
- else if (strstr(vendor, "Intel") ||
- /* src/mesa/drivers/dri/intel/intel_context.c */
- strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) {
- GPG.device = GPU_DEVICE_INTEL;
- GPG.driver = GPU_DRIVER_OFFICIAL;
-
- if (strstr(renderer, "UHD Graphics") ||
- /* Not UHD but affected by the same bugs. */
- strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2") ||
- strstr(renderer, "Whiskey Lake")) {
- GPG.device |= GPU_DEVICE_INTEL_UHD;
- }
- }
- else if ((strstr(renderer, "Mesa DRI R")) ||
- (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
- (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) ||
- (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
- (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) {
- GPG.device = GPU_DEVICE_ATI;
- GPG.driver = GPU_DRIVER_OPENSOURCE;
- }
- else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
- GPG.device = GPU_DEVICE_NVIDIA;
- GPG.driver = GPU_DRIVER_OPENSOURCE;
- }
- else if (strstr(vendor, "Mesa")) {
- GPG.device = GPU_DEVICE_SOFTWARE;
- GPG.driver = GPU_DRIVER_SOFTWARE;
- }
- else if (strstr(vendor, "Microsoft")) {
- GPG.device = GPU_DEVICE_SOFTWARE;
- GPG.driver = GPU_DRIVER_SOFTWARE;
- }
- else if (strstr(renderer, "Apple Software Renderer")) {
- GPG.device = GPU_DEVICE_SOFTWARE;
- GPG.driver = GPU_DRIVER_SOFTWARE;
- }
- else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) {
- GPG.device = GPU_DEVICE_SOFTWARE;
- GPG.driver = GPU_DRIVER_SOFTWARE;
- }
- else {
- printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
- printf("Detected OpenGL configuration:\n");
- printf("Vendor: %s\n", vendor);
- printf("Renderer: %s\n", renderer);
- GPG.device = GPU_DEVICE_ANY;
- GPG.driver = GPU_DRIVER_ANY;
- }
+} // namespace blender::gpu
- /* Detect support level */
- if (!GLEW_VERSION_3_3) {
- GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED;
- }
- else {
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
- /* Old Intel drivers with known bugs that cause material properties to crash.
- * Version Build 10.18.14.5067 is the latest available and appears to be working
- * ok with our workarounds, so excluded from this list. */
- if (strstr(version, "Build 7.14") || strstr(version, "Build 7.15") ||
- strstr(version, "Build 8.15") || strstr(version, "Build 9.17") ||
- strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") ||
- strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") ||
- strstr(version, "Build 10.18.14.4")) {
- GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED;
- }
- }
- }
- GPG.support_key = gpu_platform_create_key(GPG.support_level, vendor, renderer, version);
- GPG.gpu_name = gpu_platform_create_gpu_name(vendor, renderer, version);
- GPG.initialized = true;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name C-API
+ * \{ */
+
+using namespace blender::gpu;
+
+eGPUSupportLevel GPU_platform_support_level(void)
+{
+ return GPG.support_level;
}
-void gpu_platform_exit(void)
+const char *GPU_platform_support_level_key(void)
{
- MEM_SAFE_FREE(GPG.support_key);
- MEM_SAFE_FREE(GPG.gpu_name);
+ return GPG.support_key;
+}
+
+const char *GPU_platform_gpu_name(void)
+{
+ return GPG.gpu_name;
}
+
+/* GPU Types */
+bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
+{
+ return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver);
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh
new file mode 100644
index 00000000000..e882672fdda
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_platform_private.hh
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "GPU_platform.h"
+
+namespace blender::gpu {
+
+class GPUPlatformGlobal {
+ public:
+ bool initialized = false;
+ eGPUDeviceType device;
+ eGPUOSType os;
+ eGPUDriverType driver;
+ eGPUSupportLevel support_level;
+ char *support_key = nullptr;
+ char *gpu_name = nullptr;
+
+ public:
+ void create_key(eGPUSupportLevel support_level,
+ const char *vendor,
+ const char *renderer,
+ const char *version);
+
+ void create_gpu_name(const char *vendor, const char *renderer, const char *version);
+
+ void clear(void);
+};
+
+extern GPUPlatformGlobal GPG;
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 505ac3b0278..310a432c102 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -24,14 +24,6 @@
extern "C" {
#endif
-/* call this before running any of the functions below */
-void gpu_platform_init(void);
-void gpu_platform_exit(void);
-
-/* call this before running any of the functions below */
-void gpu_extensions_init(void);
-void gpu_extensions_exit(void);
-
/* gpu_pbvh.c */
void gpu_pbvh_init(void);
void gpu_pbvh_exit(void);
diff --git a/source/blender/gpu/intern/gpu_query.cc b/source/blender/gpu/intern/gpu_query.cc
new file mode 100644
index 00000000000..ad9b6d21420
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_query.cc
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_query.hh"
+
+using namespace blender::gpu;
+
+/* TODO(fclem) Make the associated C-API to use inside DRW profiler. */
diff --git a/source/blender/gpu/intern/gpu_query.hh b/source/blender/gpu/intern/gpu_query.hh
new file mode 100644
index 00000000000..5e3159a94f7
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_query.hh
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_span.hh"
+
+namespace blender::gpu {
+
+typedef enum GPUQueryType {
+ GPU_QUERY_OCCLUSION = 0,
+} GPUQueryType;
+
+class QueryPool {
+ public:
+ virtual ~QueryPool(){};
+
+ /**
+ * Will start and end the query at this index inside the pool. The pool will resize
+ * automatically but does not support sparse allocation. So prefer using consecutive indices.
+ */
+ virtual void init(GPUQueryType type) = 0;
+
+ /**
+ * Will start and end the query at this index inside the pool.
+ * The pool will resize automatically.
+ */
+ virtual void begin_query(void) = 0;
+ virtual void end_query(void) = 0;
+
+ /**
+ * Must be fed with a buffer large enough to contain all the queries issued.
+ * IMPORTANT: Result for each query can be either binary or represent the number of samples
+ * drawn.
+ */
+ virtual void get_occlusion_result(MutableSpan<uint32_t> r_values) = 0;
+};
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index c3ccb68a998..769b52bf593 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -346,16 +346,9 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c
ps->gl.rect_depth = depth_buf_malloc(rect_len);
/* set initial 'far' value */
-#if 0
- glReadPixels(UNPACK4(ps->gl.clip_readpixels),
- GL_DEPTH_COMPONENT,
- GL_UNSIGNED_INT,
- ps->gl.rect_depth->buf);
-#else
for (uint i = 0; i < rect_len; i++) {
ps->gl.rect_depth->buf[i] = DEPTH_MAX;
}
-#endif
ps->gl.is_init = false;
ps->gl.prev_id = 0;
@@ -486,10 +479,9 @@ bool gpu_select_pick_load_id(uint id, bool end)
}
const uint rect_len = ps->src.rect_len;
- glReadPixels(UNPACK4(ps->gl.clip_readpixels),
- GL_DEPTH_COMPONENT,
- GL_UNSIGNED_INT,
- ps->gl.rect_depth_test->buf);
+ GPUFrameBuffer *fb = GPU_framebuffer_active_get();
+ GPU_framebuffer_read_depth(
+ fb, UNPACK4(ps->gl.clip_readpixels), GPU_DATA_UNSIGNED_INT, ps->gl.rect_depth_test->buf);
/* perform initial check since most cases the array remains unchanged */
bool do_pass = false;
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
index e364b78bff2..f9a1aea8338 100644
--- a/source/blender/gpu/intern/gpu_select_private.h
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -25,6 +25,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* gpu_select_pick */
void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode);
bool gpu_select_pick_load_id(uint id, bool end);
@@ -42,3 +46,7 @@ bool gpu_select_query_load_id(uint id);
uint gpu_select_query_end(void);
#define SELECT_ID_NONE ((uint)0xffffffff)
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 45d52b22664..1b54cbff5dd 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.c
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include "GPU_framebuffer.h"
-#include "GPU_glew.h"
#include "GPU_select.h"
#include "GPU_state.h"
@@ -35,24 +34,25 @@
#include "BLI_rect.h"
+#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
+
+#include "gpu_backend.hh"
+#include "gpu_query.hh"
#include "gpu_select_private.h"
-/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
-#define ALLOC_QUERIES 200
+using namespace blender;
+using namespace blender::gpu;
-typedef struct GPUQueryState {
+typedef struct GPUSelectQueryState {
/* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
bool query_issued;
- /* array holding the OpenGL query identifiers */
- uint *queries;
- /* array holding the id corresponding to each query */
- uint *id;
- /* number of queries in *queries and *id */
- uint num_of_queries;
- /* index to the next query to start */
- uint active_query;
+ /* GPU queries abstraction. Contains an array of queries. */
+ QueryPool *queries;
+ /* Array holding the id corresponding id to each query. */
+ Vector<uint> *ids;
/* cache on initialization */
uint (*buffer)[4];
/* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
@@ -67,29 +67,23 @@ typedef struct GPUQueryState {
int scissor[4];
eGPUWriteMask write_mask;
eGPUDepthTest depth_test;
-} GPUQueryState;
+} GPUSelectQueryState;
-static GPUQueryState g_query_state = {0};
+static GPUSelectQueryState g_query_state = {0};
void gpu_select_query_begin(
uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits)
{
g_query_state.query_issued = false;
- g_query_state.active_query = 0;
- g_query_state.num_of_queries = 0;
g_query_state.bufsize = bufsize;
g_query_state.buffer = buffer;
g_query_state.mode = mode;
g_query_state.index = 0;
g_query_state.oldhits = oldhits;
- g_query_state.num_of_queries = ALLOC_QUERIES;
-
- g_query_state.queries = MEM_mallocN(
- g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries");
- g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id),
- "gpu selection ids");
- glGenQueries(g_query_state.num_of_queries, g_query_state.queries);
+ g_query_state.ids = new Vector<uint>();
+ g_query_state.queries = GPUBackend::get()->querypool_alloc();
+ g_query_state.queries->init(GPU_QUERY_OCCLUSION);
g_query_state.write_mask = GPU_write_mask_get();
g_query_state.depth_test = GPU_depth_test_get();
@@ -133,21 +127,11 @@ void gpu_select_query_begin(
bool gpu_select_query_load_id(uint id)
{
if (g_query_state.query_issued) {
- glEndQuery(GL_SAMPLES_PASSED);
- }
- /* if required, allocate extra queries */
- if (g_query_state.active_query == g_query_state.num_of_queries) {
- g_query_state.num_of_queries += ALLOC_QUERIES;
- g_query_state.queries = MEM_reallocN(
- g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
- g_query_state.id = MEM_reallocN(g_query_state.id,
- g_query_state.num_of_queries * sizeof(*g_query_state.id));
- glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ g_query_state.queries->end_query();
}
- glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]);
- g_query_state.id[g_query_state.active_query] = id;
- g_query_state.active_query++;
+ g_query_state.queries->begin_query();
+ g_query_state.ids->append(id);
g_query_state.query_issued = true;
if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) {
@@ -158,39 +142,33 @@ bool gpu_select_query_load_id(uint id)
g_query_state.index++;
return true;
}
-
return false;
}
}
-
return true;
}
uint gpu_select_query_end(void)
{
- int i;
-
uint hits = 0;
const uint maxhits = g_query_state.bufsize;
if (g_query_state.query_issued) {
- glEndQuery(GL_SAMPLES_PASSED);
+ g_query_state.queries->end_query();
}
- for (i = 0; i < g_query_state.active_query; i++) {
- uint result = 0;
- /* We are not using GL_QUERY_RESULT_AVAILABLE and sleep to wait for results,
- * because it causes lagging on Windows/NVIDIA, see T61474. */
- glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
- if (result > 0) {
- if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
+ Span<uint> ids = *g_query_state.ids;
+ Vector<uint32_t> result(ids.size());
+ g_query_state.queries->get_occlusion_result(result);
+ for (int i = 0; i < result.size(); i++) {
+ if (result[i] != 0) {
+ if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
if (hits < maxhits) {
g_query_state.buffer[hits][0] = 1;
g_query_state.buffer[hits][1] = 0xFFFF;
g_query_state.buffer[hits][2] = 0xFFFF;
- g_query_state.buffer[hits][3] = g_query_state.id[i];
-
+ g_query_state.buffer[hits][3] = ids[i];
hits++;
}
else {
@@ -202,7 +180,7 @@ uint gpu_select_query_end(void)
int j;
/* search in buffer and make selected object first */
for (j = 0; j < g_query_state.oldhits; j++) {
- if (g_query_state.buffer[j][3] == g_query_state.id[i]) {
+ if (g_query_state.buffer[j][3] == ids[i]) {
g_query_state.buffer[j][1] = 0;
g_query_state.buffer[j][2] = 0;
}
@@ -212,9 +190,8 @@ uint gpu_select_query_end(void)
}
}
- glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
- MEM_freeN(g_query_state.queries);
- MEM_freeN(g_query_state.id);
+ delete g_query_state.queries;
+ delete g_query_state.ids;
GPU_write_mask(g_query_state.write_mask);
GPU_depth_test(g_query_state.depth_test);
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index fd01160cff6..1bd076f96f8 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -36,7 +36,7 @@
#include "DNA_space_types.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
@@ -52,11 +52,6 @@ extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
using namespace blender;
using namespace blender::gpu;
-/** Opaque type hidding blender::gpu::Shader */
-struct GPUShader {
- char _pad[1];
-};
-
/* -------------------------------------------------------------------- */
/** \name Debug functions
* \{ */
@@ -333,12 +328,12 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
return NULL;
};
- return reinterpret_cast<GPUShader *>(shader);
+ return wrap(shader);
}
void GPU_shader_free(GPUShader *shader)
{
- delete reinterpret_cast<Shader *>(shader);
+ delete unwrap(shader);
}
/** \} */
@@ -460,9 +455,9 @@ struct GPUShader *GPU_shader_create_from_arrays_impl(
void GPU_shader_bind(GPUShader *gpu_shader)
{
- Shader *shader = reinterpret_cast<Shader *>(gpu_shader);
+ Shader *shader = unwrap(gpu_shader);
- GPUContext *ctx = GPU_context_active_get();
+ Context *ctx = Context::get();
if (ctx->shader != shader) {
ctx->shader = shader;
@@ -479,9 +474,9 @@ void GPU_shader_bind(GPUShader *gpu_shader)
void GPU_shader_unbind(void)
{
#ifndef NDEBUG
- GPUContext *ctx = GPU_context_active_get();
+ Context *ctx = Context::get();
if (ctx->shader) {
- reinterpret_cast<Shader *>(ctx->shader)->unbind();
+ ctx->shader->unbind();
}
ctx->shader = NULL;
#endif
@@ -497,12 +492,12 @@ void GPU_shader_unbind(void)
bool GPU_shader_transform_feedback_enable(GPUShader *shader, GPUVertBuf *vertbuf)
{
- return reinterpret_cast<Shader *>(shader)->transform_feedback_enable(vertbuf);
+ return unwrap(shader)->transform_feedback_enable(vertbuf);
}
void GPU_shader_transform_feedback_disable(GPUShader *shader)
{
- reinterpret_cast<Shader *>(shader)->transform_feedback_disable();
+ unwrap(shader)->transform_feedback_disable();
}
/** \} */
@@ -513,48 +508,48 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader)
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
const ShaderInput *uniform = interface->uniform_get(name);
return uniform ? uniform->location : -1;
}
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
return interface->uniform_builtin((GPUUniformBuiltin)builtin);
}
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
}
/* DEPRECATED. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
const ShaderInput *ubo = interface->ubo_get(name);
return ubo ? ubo->location : -1;
}
int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
const ShaderInput *ubo = interface->ubo_get(name);
return ubo ? ubo->binding : -1;
}
int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
const ShaderInput *tex = interface->uniform_get(name);
return tex ? tex->binding : -1;
}
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
{
- ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface;
+ ShaderInterface *interface = unwrap(shader)->interface;
const ShaderInput *attr = interface->attr_get(name);
return attr ? attr->location : -1;
}
@@ -581,13 +576,13 @@ int GPU_shader_get_program(GPUShader *UNUSED(shader))
void GPU_shader_uniform_vector(
GPUShader *shader, int loc, int len, int arraysize, const float *value)
{
- reinterpret_cast<Shader *>(shader)->uniform_float(loc, len, arraysize, value);
+ unwrap(shader)->uniform_float(loc, len, arraysize, value);
}
void GPU_shader_uniform_vector_int(
GPUShader *shader, int loc, int len, int arraysize, const int *value)
{
- reinterpret_cast<Shader *>(shader)->uniform_int(loc, len, arraysize, value);
+ unwrap(shader)->uniform_int(loc, len, arraysize, value);
}
void GPU_shader_uniform_int(GPUShader *shader, int location, int value)
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index ed95a236da5..f528e67a80a 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -35,7 +35,6 @@
#include "DNA_space_types.h"
-#include "GPU_extensions.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh
index fa086892760..b7acc0f9353 100644
--- a/source/blender/gpu/intern/gpu_shader_private.hh
+++ b/source/blender/gpu/intern/gpu_shader_private.hh
@@ -23,8 +23,8 @@
#include "BLI_span.hh"
#include "GPU_shader.h"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_shader_interface.hh"
+#include "gpu_vertex_buffer_private.hh"
namespace blender {
namespace gpu {
@@ -73,6 +73,20 @@ class Shader {
void print_errors(Span<const char *> sources, char *log, const char *stage);
};
+/* Syntacting suggar. */
+static inline GPUShader *wrap(Shader *vert)
+{
+ return reinterpret_cast<GPUShader *>(vert);
+}
+static inline Shader *unwrap(GPUShader *vert)
+{
+ return reinterpret_cast<Shader *>(vert);
+}
+static inline const Shader *unwrap(const GPUShader *vert)
+{
+ return reinterpret_cast<const Shader *>(vert);
+}
+
} // namespace gpu
} // namespace blender
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index 478fd639cdd..529c8795327 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -30,7 +30,6 @@
#include "BKE_global.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_state.h"
@@ -42,7 +41,7 @@ using namespace blender::gpu;
#define SET_STATE(_prefix, _state, _value) \
do { \
- GPUStateManager *stack = GPU_context_active_get()->state_manager; \
+ GPUStateManager *stack = Context::get()->state_manager; \
auto &state_object = stack->_prefix##state; \
state_object._state = (_value); \
} while (0)
@@ -106,7 +105,7 @@ void GPU_write_mask(eGPUWriteMask mask)
void GPU_color_mask(bool r, bool g, bool b, bool a)
{
- GPUStateManager *stack = GPU_context_active_get()->state_manager;
+ GPUStateManager *stack = Context::get()->state_manager;
auto &state = stack->state;
uint32_t write_mask = state.write_mask;
SET_FLAG_FROM_TEST(write_mask, r, (uint32_t)GPU_WRITE_RED);
@@ -118,7 +117,7 @@ void GPU_color_mask(bool r, bool g, bool b, bool a)
void GPU_depth_mask(bool depth)
{
- GPUStateManager *stack = GPU_context_active_get()->state_manager;
+ GPUStateManager *stack = Context::get()->state_manager;
auto &state = stack->state;
uint32_t write_mask = state.write_mask;
SET_FLAG_FROM_TEST(write_mask, depth, (uint32_t)GPU_WRITE_DEPTH);
@@ -143,7 +142,7 @@ void GPU_state_set(eGPUWriteMask write_mask,
eGPUStencilOp stencil_op,
eGPUProvokingVertex provoking_vert)
{
- GPUStateManager *stack = GPU_context_active_get()->state_manager;
+ GPUStateManager *stack = Context::get()->state_manager;
auto &state = stack->state;
state.write_mask = (uint32_t)write_mask;
state.blend = (uint32_t)blend;
@@ -162,7 +161,7 @@ void GPU_state_set(eGPUWriteMask write_mask,
void GPU_depth_range(float near, float far)
{
- GPUStateManager *stack = GPU_context_active_get()->state_manager;
+ GPUStateManager *stack = Context::get()->state_manager;
auto &state = stack->mutable_state;
copy_v2_fl2(state.depth_range, near, far);
}
@@ -183,7 +182,7 @@ void GPU_point_size(float size)
/* TODO remove and use program point size everywhere */
void GPU_program_point_size(bool enable)
{
- GPUStateManager *stack = GPU_context_active_get()->state_manager;
+ GPUStateManager *stack = Context::get()->state_manager;
auto &state = stack->mutable_state;
/* Set point size sign negative to disable. */
state.point_size = fabsf(state.point_size) * (enable ? 1 : -1);
@@ -191,19 +190,19 @@ void GPU_program_point_size(bool enable)
void GPU_scissor_test(bool enable)
{
- GPU_context_active_get()->active_fb->scissor_test_set(enable);
+ Context::get()->active_fb->scissor_test_set(enable);
}
void GPU_scissor(int x, int y, int width, int height)
{
int scissor_rect[4] = {x, y, width, height};
- GPU_context_active_get()->active_fb->scissor_set(scissor_rect);
+ Context::get()->active_fb->scissor_set(scissor_rect);
}
void GPU_viewport(int x, int y, int width, int height)
{
int viewport_rect[4] = {x, y, width, height};
- GPU_context_active_get()->active_fb->viewport_set(viewport_rect);
+ Context::get()->active_fb->viewport_set(viewport_rect);
}
void GPU_stencil_reference_set(uint reference)
@@ -229,43 +228,43 @@ void GPU_stencil_compare_mask_set(uint compare_mask)
eGPUBlend GPU_blend_get()
{
- GPUState &state = GPU_context_active_get()->state_manager->state;
+ GPUState &state = Context::get()->state_manager->state;
return (eGPUBlend)state.blend;
}
eGPUWriteMask GPU_write_mask_get()
{
- GPUState &state = GPU_context_active_get()->state_manager->state;
+ GPUState &state = Context::get()->state_manager->state;
return (eGPUWriteMask)state.write_mask;
}
uint GPU_stencil_mask_get()
{
- GPUStateMutable &state = GPU_context_active_get()->state_manager->mutable_state;
+ GPUStateMutable &state = Context::get()->state_manager->mutable_state;
return state.stencil_write_mask;
}
eGPUDepthTest GPU_depth_test_get()
{
- GPUState &state = GPU_context_active_get()->state_manager->state;
+ GPUState &state = Context::get()->state_manager->state;
return (eGPUDepthTest)state.depth_test;
}
eGPUStencilTest GPU_stencil_test_get()
{
- GPUState &state = GPU_context_active_get()->state_manager->state;
+ GPUState &state = Context::get()->state_manager->state;
return (eGPUStencilTest)state.stencil_test;
}
void GPU_scissor_get(int coords[4])
{
- GPU_context_active_get()->active_fb->scissor_get(coords);
+ Context::get()->active_fb->scissor_get(coords);
}
void GPU_viewport_size_get_f(float coords[4])
{
int viewport[4];
- GPU_context_active_get()->active_fb->viewport_get(viewport);
+ Context::get()->active_fb->viewport_get(viewport);
for (int i = 0; i < 4; i++) {
coords[i] = viewport[i];
}
@@ -273,12 +272,12 @@ void GPU_viewport_size_get_f(float coords[4])
void GPU_viewport_size_get_i(int coords[4])
{
- GPU_context_active_get()->active_fb->viewport_get(coords);
+ Context::get()->active_fb->viewport_get(coords);
}
bool GPU_depth_mask_get(void)
{
- GPUState &state = GPU_context_active_get()->state_manager->state;
+ GPUState &state = Context::get()->state_manager->state;
return (state.write_mask & GPU_WRITE_DEPTH) != 0;
}
@@ -296,17 +295,12 @@ bool GPU_mipmap_enabled(void)
void GPU_flush(void)
{
- glFlush();
+ Context::get()->flush();
}
void GPU_finish(void)
{
- glFinish();
-}
-
-void GPU_unpack_row_length_set(uint len)
-{
- glPixelStorei(GL_UNPACK_ROW_LENGTH, len);
+ Context::get()->finish();
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh
index 6ce240df108..9fee45e7bd4 100644
--- a/source/blender/gpu/intern/gpu_state_private.hh
+++ b/source/blender/gpu/intern/gpu_state_private.hh
@@ -166,6 +166,8 @@ class GPUStateManager {
virtual void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) = 0;
virtual void texture_unbind(Texture *tex) = 0;
virtual void texture_unbind_all(void) = 0;
+
+ virtual void texture_unpack_row_length_set(uint len) = 0;
};
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index ad9b690683c..b22fd53f0f6 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -190,7 +190,7 @@ uint GPU_texture_memory_usage_get(void)
return 0;
}
-/* ------ Texture Creation ------ */
+/* ------ Creation ------ */
static inline GPUTexture *gpu_texture_create(const char *name,
const int w,
@@ -329,6 +329,8 @@ GPUTexture *GPU_texture_create_error(int dimension, bool is_array)
return gpu_texture_create("invalid_tex", w, h, d, type, 1, GPU_RGBA8, pixel);
}
+/* ------ Update ------ */
+
void GPU_texture_update_mipmap(GPUTexture *tex_,
int miplvl,
eGPUDataFormat data_format,
@@ -365,8 +367,8 @@ void *GPU_texture_read(GPUTexture *tex_, eGPUDataFormat data_format, int miplvl)
* Fills the whole texture with the same data for all pixels.
* \warning Only work for 2D texture for now.
* \warning Only clears the mip 0 of the texture.
- * \param data_format data format of the pixel data.
- * \param data 1 pixel worth of data to fill the texture with.
+ * \param data_format: data format of the pixel data.
+ * \param data: 1 pixel worth of data to fill the texture with.
*/
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
@@ -380,20 +382,14 @@ void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void
reinterpret_cast<Texture *>(tex)->update(data_format, data);
}
-void GPU_invalid_tex_init(void)
-{
- /* TODO remove */
-}
-
-void GPU_invalid_tex_bind(int UNUSED(mode))
+/* Makes data interpretation aware of the source layout.
+ * Skipping pixels correctly when changing rows when doing partial update.*/
+void GPU_unpack_row_length_set(uint len)
{
- /* TODO remove */
+ Context::get()->state_manager->texture_unpack_row_length_set(len);
}
-void GPU_invalid_tex_free(void)
-{
- /* TODO remove */
-}
+/* ------ Binding ------ */
void GPU_texture_bind_ex(GPUTexture *tex_,
eGPUSamplerState state,
@@ -402,24 +398,24 @@ void GPU_texture_bind_ex(GPUTexture *tex_,
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
state = (state >= GPU_SAMPLER_MAX) ? tex->sampler_state : state;
- GPU_context_active_get()->state_manager->texture_bind(tex, state, unit);
+ Context::get()->state_manager->texture_bind(tex, state, unit);
}
void GPU_texture_bind(GPUTexture *tex_, int unit)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
- GPU_context_active_get()->state_manager->texture_bind(tex, tex->sampler_state, unit);
+ Context::get()->state_manager->texture_bind(tex, tex->sampler_state, unit);
}
void GPU_texture_unbind(GPUTexture *tex_)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
- GPU_context_active_get()->state_manager->texture_unbind(tex);
+ Context::get()->state_manager->texture_unbind(tex);
}
void GPU_texture_unbind_all(void)
{
- GPU_context_active_get()->state_manager->texture_unbind_all();
+ Context::get()->state_manager->texture_unbind_all();
}
void GPU_texture_generate_mipmap(GPUTexture *tex)
@@ -540,12 +536,6 @@ eGPUTextureFormat GPU_texture_format(const GPUTexture *tex)
return reinterpret_cast<const Texture *>(tex)->format_get();
}
-/* TODO remove */
-int GPU_texture_samples(const GPUTexture *UNUSED(tex))
-{
- return 0;
-}
-
bool GPU_texture_depth(const GPUTexture *tex)
{
return (reinterpret_cast<const Texture *>(tex)->format_flag_get() & GPU_FORMAT_DEPTH) != 0;
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index 8f01d28e65e..04156632c5e 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -66,8 +66,12 @@ ENUM_OPERATORS(eGPUTextureType)
#endif
/* Maximum number of FBOs a texture can be attached to. */
-#define GPU_TEX_MAX_FBO_ATTACHED 13
+#define GPU_TEX_MAX_FBO_ATTACHED 14
+/**
+ * Implementation of Textures.
+ * Base class which is then specialized for each implementation (GL, VK, ...).
+ **/
class Texture {
public:
/** Internal Sampler state. */
@@ -241,6 +245,20 @@ class Texture {
virtual bool init_internal(GPUVertBuf *vbo) = 0;
};
+/* Syntacting suggar. */
+static inline GPUTexture *wrap(Texture *vert)
+{
+ return reinterpret_cast<GPUTexture *>(vert);
+}
+static inline Texture *unwrap(GPUTexture *vert)
+{
+ return reinterpret_cast<Texture *>(vert);
+}
+static inline const Texture *unwrap(const GPUTexture *vert)
+{
+ return reinterpret_cast<const Texture *>(vert);
+}
+
#undef DEBUG_NAME_LEN
inline size_t to_bytesize(eGPUTextureFormat format)
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc
index 94aa6bd76ab..2dea98f03ca 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer.cc
+++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc
@@ -32,8 +32,6 @@
#include "GPU_material.h"
-#include "GPU_extensions.h"
-
#include "GPU_uniform_buffer.h"
#include "gpu_uniform_buffer_private.hh"
@@ -47,7 +45,6 @@ UniformBuf::UniformBuf(size_t size, const char *name)
{
/* Make sure that UBO is padded to size of vec4 */
BLI_assert((size % 16) == 0);
- BLI_assert(size <= GPU_max_ubo_size());
size_in_bytes_ = size;
@@ -201,7 +198,7 @@ GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const cha
if (data != NULL) {
ubo->update(data);
}
- return reinterpret_cast<GPUUniformBuf *>(ubo);
+ return wrap(ubo);
}
/**
@@ -225,27 +222,27 @@ GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *nam
UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(buffer_size, name);
/* Defer data upload. */
ubo->attach_data(data);
- return reinterpret_cast<GPUUniformBuf *>(ubo);
+ return wrap(ubo);
}
void GPU_uniformbuf_free(GPUUniformBuf *ubo)
{
- delete reinterpret_cast<UniformBuf *>(ubo);
+ delete unwrap(ubo);
}
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
{
- reinterpret_cast<UniformBuf *>(ubo)->update(data);
+ unwrap(ubo)->update(data);
}
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
{
- reinterpret_cast<UniformBuf *>(ubo)->bind(slot);
+ unwrap(ubo)->bind(slot);
}
void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
{
- reinterpret_cast<UniformBuf *>(ubo)->unbind();
+ unwrap(ubo)->unbind();
}
void GPU_uniformbuf_unbind_all(void)
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
index cf6447ccd37..00d10776864 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
@@ -63,6 +63,20 @@ class UniformBuf {
}
};
+/* Syntacting suggar. */
+static inline GPUUniformBuf *wrap(UniformBuf *vert)
+{
+ return reinterpret_cast<GPUUniformBuf *>(vert);
+}
+static inline UniformBuf *unwrap(GPUUniformBuf *vert)
+{
+ return reinterpret_cast<UniformBuf *>(vert);
+}
+static inline const UniformBuf *unwrap(const GPUUniformBuf *vert)
+{
+ return reinterpret_cast<const UniformBuf *>(vert);
+}
+
#undef DEBUG_NAME_LEN
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 61af0a215a9..f1de0a2ac96 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -29,6 +29,10 @@
namespace blender::gpu {
+/**
+ * Implementation of Vertex Buffers.
+ * Base class which is then specialized for each implementation (GL, VK, ...).
+ **/
class VertBuf {
public:
static size_t memory_usage;
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
new file mode 100644
index 00000000000..c8d57a20a38
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -0,0 +1,370 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BKE_global.h"
+
+#include "gpu_capabilities_private.hh"
+#include "gpu_platform_private.hh"
+
+#include "glew-mx.h"
+
+#include "gl_debug.hh"
+
+#include "gl_backend.hh"
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name Platform
+ * \{ */
+
+void GLBackend::platform_init(void)
+{
+ BLI_assert(!GPG.initialized);
+ GPG.initialized = true;
+
+#ifdef _WIN32
+ GPG.os = GPU_OS_WIN;
+#elif defined(__APPLE__)
+ GPG.os = GPU_OS_MAC;
+#else
+ GPG.os = GPU_OS_UNIX;
+#endif
+
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ const char *renderer = (const char *)glGetString(GL_RENDERER);
+ const char *version = (const char *)glGetString(GL_VERSION);
+
+ if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
+ GPG.device = GPU_DEVICE_ATI;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "NVIDIA")) {
+ GPG.device = GPU_DEVICE_NVIDIA;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "Intel") ||
+ /* src/mesa/drivers/dri/intel/intel_context.c */
+ strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) {
+ GPG.device = GPU_DEVICE_INTEL;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+
+ if (strstr(renderer, "UHD Graphics") ||
+ /* Not UHD but affected by the same bugs. */
+ strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2") ||
+ strstr(renderer, "Whiskey Lake")) {
+ GPG.device |= GPU_DEVICE_INTEL_UHD;
+ }
+ }
+ else if ((strstr(renderer, "Mesa DRI R")) ||
+ (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
+ (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) ||
+ (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
+ (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) {
+ GPG.device = GPU_DEVICE_ATI;
+ GPG.driver = GPU_DRIVER_OPENSOURCE;
+ }
+ else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
+ GPG.device = GPU_DEVICE_NVIDIA;
+ GPG.driver = GPU_DRIVER_OPENSOURCE;
+ }
+ else if (strstr(vendor, "Mesa")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(vendor, "Microsoft")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(renderer, "Apple Software Renderer")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else {
+ printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
+ printf("Detected OpenGL configuration:\n");
+ printf("Vendor: %s\n", vendor);
+ printf("Renderer: %s\n", renderer);
+ GPG.device = GPU_DEVICE_ANY;
+ GPG.driver = GPU_DRIVER_ANY;
+ }
+
+ /* Detect support level */
+ if (!GLEW_VERSION_3_3) {
+ GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED;
+ }
+ else {
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
+ /* Old Intel drivers with known bugs that cause material properties to crash.
+ * Version Build 10.18.14.5067 is the latest available and appears to be working
+ * ok with our workarounds, so excluded from this list. */
+ if (strstr(version, "Build 7.14") || strstr(version, "Build 7.15") ||
+ strstr(version, "Build 8.15") || strstr(version, "Build 9.17") ||
+ strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") ||
+ strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") ||
+ strstr(version, "Build 10.18.14.4")) {
+ GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED;
+ }
+ }
+ }
+ GPG.create_key(GPG.support_level, vendor, renderer, version);
+ GPG.create_gpu_name(vendor, renderer, version);
+}
+
+void GLBackend::platform_exit(void)
+{
+ BLI_assert(GPG.initialized);
+ GPG.clear();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Capabilities
+ * \{ */
+
+static bool detect_mip_render_workaround(void)
+{
+ int cube_size = 2;
+ float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f};
+ float *source_pix = (float *)MEM_callocN(sizeof(float[4]) * cube_size * cube_size * 6, __func__);
+
+ /* NOTE: Debug layers are not yet enabled. Force use of glGetError. */
+ debug::check_gl_error("Cubemap Workaround Start");
+ /* Not using GPU API since it is not yet fully initialized. */
+ GLuint tex, fb;
+ /* Create cubemap with 2 mip level. */
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
+ for (int mip = 0; mip < 2; mip++) {
+ for (int i = 0; i < 6; i++) {
+ const int width = cube_size / (1 << mip);
+ GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+ glTexImage2D(target, mip, GL_RGBA16F, width, width, 0, GL_RGBA, GL_FLOAT, source_pix);
+ }
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
+ /* Attach and clear mip 1. */
+ glGenFramebuffers(1, &fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 1);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0);
+ glClearColor(UNPACK4(clear_color));
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDrawBuffer(GL_BACK);
+ /* Read mip 1. If color is not the same as the clear_color, the rendering failed. */
+ glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 1, GL_RGBA, GL_FLOAT, source_pix);
+ bool enable_workaround = !equals_v4v4(clear_color, source_pix);
+ MEM_freeN(source_pix);
+
+ glDeleteFramebuffers(1, &fb);
+ glDeleteTextures(1, &tex);
+
+ debug::check_gl_error("Cubemap Workaround End9");
+
+ return enable_workaround;
+}
+
+static void detect_workarounds(void)
+{
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ const char *renderer = (const char *)glGetString(GL_RENDERER);
+ const char *version = (const char *)glGetString(GL_VERSION);
+
+ if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) {
+ printf("\n");
+ printf("GL: Forcing workaround usage and disabling extensions.\n");
+ printf(" OpenGL identification strings\n");
+ printf(" vendor: %s\n", vendor);
+ printf(" renderer: %s\n", renderer);
+ printf(" version: %s\n\n", version);
+ GCaps.depth_blitting_workaround = true;
+ GCaps.mip_render_workaround = true;
+ GLContext::unused_fb_slot_workaround = true;
+ GLContext::texture_copy_workaround = true;
+ /* Turn off extensions. */
+ GLContext::base_instance_support = false;
+ GLContext::texture_cube_map_array_support = false;
+ return;
+ }
+
+ /* Some Intel drivers have issues with using mips as framebuffer targets if
+ * GL_TEXTURE_MAX_LEVEL is higher than the target mip.
+ * Only check at the end after all other workarounds because this uses the drawing code. */
+ GCaps.mip_render_workaround = detect_mip_render_workaround();
+ /* Limit support for GLEW_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800
+ * (TeraScale) report that they support GLEW_ARB_base_instance, but the driver does not support
+ * GLEW_ARB_draw_indirect as it has an OpenGL3 context what also matches the minimum needed
+ * requirements.
+ *
+ * We use it as a target for glMapBuffer(Range) what is part of the OpenGL 4 API. So better
+ * disable it when we don't have an OpenGL4 context (See T77657) */
+ if (!GLEW_VERSION_4_0) {
+ GLContext::base_instance_support = false;
+ }
+ /* The renderers include:
+ * Mobility Radeon HD 5000;
+ * Radeon HD 7500M;
+ * Radeon HD 7570M;
+ * Radeon HD 7600M;
+ * And many others... */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
+ (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") ||
+ strstr(version, "4.5.13422"))) {
+ GLContext::unused_fb_slot_workaround = true;
+ GCaps.broken_amd_driver = true;
+ }
+ /* We have issues with this specific renderer. (see T74024) */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
+ strstr(renderer, "AMD VERDE")) {
+ GLContext::unused_fb_slot_workaround = true;
+ GCaps.broken_amd_driver = true;
+ }
+ /* Fix slowdown on this particular driver. (see T77641) */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
+ strstr(version, "Mesa 19.3.4")) {
+ GCaps.broken_amd_driver = true;
+ }
+ /* There is an issue with the #glBlitFramebuffer on MacOS with radeon pro graphics.
+ * Blitting depth with#GL_DEPTH24_STENCIL8 is buggy so the workaround is to use
+ * #GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will
+ * still be broken. */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) {
+ if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") ||
+ strstr(renderer, "AMD Radeon RX")) {
+ GCaps.depth_blitting_workaround = true;
+ }
+ }
+ /* Limit this fix to older hardware with GL < 4.5. This means Broadwell GPUs are
+ * covered since they only support GL 4.4 on windows.
+ * This fixes some issues with workbench anti-aliasing on Win + Intel GPU. (see T76273) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && !GLEW_VERSION_4_5) {
+ GLContext::texture_copy_workaround = true;
+ }
+ /* Special fix for theses specific GPUs.
+ * Without this workaround, blender crashes on startup. (see T72098) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
+ (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) {
+ GCaps.mip_render_workaround = true;
+ }
+ /* Intel Ivy Bridge GPU's seems to have buggy cube-map array support. (see T75943) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
+ (strstr(renderer, "HD Graphics 4000") || strstr(renderer, "HD Graphics 4400") ||
+ strstr(renderer, "HD Graphics 2500"))) {
+ GLContext::texture_cube_map_array_support = false;
+ }
+ /* Maybe not all of these drivers have problems with `GLEW_ARB_base_instance`.
+ * But it's hard to test each case.
+ * We get crashes from some crappy Intel drivers don't work well with shaders created in
+ * different rendering contexts. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY) &&
+ (strstr(version, "Build 10.18.10.3") || strstr(version, "Build 10.18.10.4") ||
+ strstr(version, "Build 10.18.10.5") || strstr(version, "Build 10.18.14.4") ||
+ strstr(version, "Build 10.18.14.5"))) {
+ GLContext::base_instance_support = false;
+ GCaps.use_main_context_workaround = true;
+ }
+ /* Somehow fixes armature display issues (see T69743). */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY) &&
+ (strstr(version, "Build 20.19.15.4285"))) {
+ GCaps.use_main_context_workaround = true;
+ }
+ /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the
+ * Mesa driver */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
+ (strstr(version, "Mesa 18.") || strstr(version, "Mesa 19.0") ||
+ strstr(version, "Mesa 19.1") || strstr(version, "Mesa 19.2"))) {
+ GLContext::unused_fb_slot_workaround = true;
+ }
+
+ /* dFdx/dFdy calculation factors, those are dependent on driver. */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) &&
+ strstr(version, "3.3.10750")) {
+ GLContext::derivative_signs[0] = 1.0;
+ GLContext::derivative_signs[1] = -1.0;
+ }
+ else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
+ if (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3186") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3165") ||
+ strstr(version, "3.1.0 - Build 9.17.10.3347") ||
+ strstr(version, "3.1.0 - Build 9.17.10.4101") ||
+ strstr(version, "3.3.0 - Build 8.15.10.2618")) {
+ GLContext::derivative_signs[0] = -1.0;
+ GLContext::derivative_signs[1] = 1.0;
+ }
+ }
+}
+
+/** Internal capabilities. */
+GLint GLContext::max_texture_3d_size;
+GLint GLContext::max_cubemap_size;
+GLint GLContext::max_ubo_size;
+GLint GLContext::max_ubo_binds;
+/** Extensions. */
+bool GLContext::base_instance_support = false;
+bool GLContext::debug_layer_support = false;
+bool GLContext::texture_cube_map_array_support = false;
+/** Workarounds. */
+bool GLContext::texture_copy_workaround = false;
+bool GLContext::unused_fb_slot_workaround = false;
+float GLContext::derivative_signs[2] = {1.0f, 1.0f};
+
+void GLBackend::capabilities_init(void)
+{
+ BLI_assert(GLEW_VERSION_3_3);
+ /* Common Capabilities. */
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GCaps.max_texture_size);
+ glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GCaps.max_texture_layers);
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_frag);
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_vert);
+ glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_geom);
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GCaps.max_textures);
+ GCaps.mem_stats_support = GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo;
+ /* GL specific capabilities. */
+ glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GLContext::max_texture_3d_size);
+ glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GLContext::max_cubemap_size);
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GLContext::max_ubo_binds);
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GLContext::max_ubo_size);
+ GLContext::base_instance_support = GLEW_ARB_base_instance;
+ GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array;
+ GLContext::debug_layer_support = (GLEW_VERSION_4_3 || GLEW_KHR_debug);
+
+ if ((G.debug & G_DEBUG_GPU) == 0) {
+ /* Disable this feature entierly when not debugging. */
+ GLContext::debug_layer_support = false;
+ }
+
+ detect_workarounds();
+}
+
+/** \} */
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index c178aa537a0..231e5811b45 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -32,6 +32,7 @@
#include "gl_drawlist.hh"
#include "gl_framebuffer.hh"
#include "gl_index_buffer.hh"
+#include "gl_query.hh"
#include "gl_shader.hh"
#include "gl_texture.hh"
#include "gl_uniform_buffer.hh"
@@ -47,11 +48,17 @@ class GLBackend : public GPUBackend {
public:
GLBackend()
{
+ /* platform_init needs to go first. */
+ GLBackend::platform_init();
+
+ GLBackend::capabilities_init();
GLTexture::samplers_init();
}
~GLBackend()
{
GLTexture::samplers_free();
+
+ GLBackend::platform_exit();
}
static GLBackend *get(void)
@@ -64,7 +71,7 @@ class GLBackend : public GPUBackend {
GLTexture::samplers_update();
};
- GPUContext *context_alloc(void *ghost_window) override
+ Context *context_alloc(void *ghost_window) override
{
return new GLContext(ghost_window, shared_orphan_list_);
};
@@ -89,6 +96,11 @@ class GLBackend : public GPUBackend {
return new GLIndexBuf();
};
+ QueryPool *querypool_alloc(void) override
+ {
+ return new GLQueryPool();
+ };
+
Shader *shader_alloc(const char *name) override
{
return new GLShader(name);
@@ -109,15 +121,16 @@ class GLBackend : public GPUBackend {
return new GLVertBuf();
};
- /* TODO remove */
- void buf_free(GLuint buf_id);
- void tex_free(GLuint tex_id);
- void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, unsigned int id)
+ GLSharedOrphanLists &shared_orphan_list_get(void)
{
- list_mutex.lock();
- orphan_list.append(id);
- list_mutex.unlock();
- }
+ return shared_orphan_list_;
+ };
+
+ private:
+ static void platform_init(void);
+ static void platform_exit(void);
+
+ static void capabilities_init(void);
};
} // namespace gpu
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index db30a57953d..b25bafad6a3 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -29,11 +29,10 @@
#include "glew-mx.h"
-#include "GPU_extensions.h"
-
#include "gpu_batch_private.hh"
#include "gpu_shader_private.hh"
+#include "gl_backend.hh"
#include "gl_context.hh"
#include "gl_debug.hh"
#include "gl_index_buffer.hh"
@@ -152,7 +151,7 @@ void GLVaoCache::remove(const GLShaderInterface *interface)
void GLVaoCache::clear(void)
{
- GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
+ GLContext *ctx = GLContext::get();
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
@@ -210,7 +209,7 @@ GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
* Reset the cache if trying to draw in another context; */
void GLVaoCache::context_check(void)
{
- GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
+ GLContext *ctx = GLContext::get();
BLI_assert(ctx);
if (context_ != ctx) {
@@ -229,7 +228,7 @@ GLuint GLVaoCache::base_instance_vao_get(GPUBatch *batch, int i_first)
{
this->context_check();
/* Make sure the interface is up to date. */
- Shader *shader = GPU_context_active_get()->shader;
+ Shader *shader = GLContext::get()->shader;
GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface);
if (interface_ != interface) {
vao_get(batch);
@@ -261,7 +260,7 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch)
{
this->context_check();
- Shader *shader = GPU_context_active_get()->shader;
+ Shader *shader = GLContext::get()->shader;
GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface);
if (interface_ != interface) {
interface_ = interface;
@@ -299,7 +298,7 @@ GLBatch::~GLBatch()
void GLBatch::bind(int i_first)
{
- GPU_context_active_get()->state_manager->apply_state();
+ GLContext::get()->state_manager->apply_state();
if (flag & GPU_BATCH_DIRTY) {
flag &= ~GPU_BATCH_DIRTY;
@@ -314,7 +313,7 @@ void GLBatch::bind(int i_first)
#endif
/* Can be removed if GL 4.2 is required. */
- if (!GPU_arb_base_instance_is_supported() && (i_first > 0)) {
+ if (!GLContext::base_instance_support && (i_first > 0)) {
glBindVertexArray(vao_cache_.base_instance_vao_get(this, i_first));
}
else {
@@ -339,7 +338,7 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count)
GLint base_index = el->index_base_;
void *v_first_ofs = el->offset_ptr(v_first);
- if (GPU_arb_base_instance_is_supported()) {
+ if (GLContext::base_instance_support) {
glDrawElementsInstancedBaseVertexBaseInstance(
gl_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first);
}
@@ -353,7 +352,7 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count)
#ifdef __APPLE__
glDisable(GL_PRIMITIVE_RESTART);
#endif
- if (GPU_arb_base_instance_is_supported()) {
+ if (GLContext::base_instance_support) {
glDrawArraysInstancedBaseInstance(gl_type, v_first, v_count, i_count, i_first);
}
else {
diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc
index 1495e665aa8..6b3b06ef12b 100644
--- a/source/blender/gpu/opengl/gl_context.cc
+++ b/source/blender/gpu/opengl/gl_context.cc
@@ -32,6 +32,7 @@
#include "GHOST_C-api.h"
#include "gpu_context_private.hh"
+#include "gpu_immediate_private.hh"
#include "gl_debug.hh"
#include "gl_immediate.hh"
@@ -80,8 +81,8 @@ GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list
front_left = new GLFrameBuffer("front_left", this, GL_FRONT_LEFT, 0, w, h);
back_left = new GLFrameBuffer("back_left", this, GL_BACK_LEFT, 0, w, h);
}
- /* TODO(fclem) enable is supported. */
- const bool supports_stereo_quad_buffer = false;
+ GLboolean supports_stereo_quad_buffer = GL_FALSE;
+ glGetBooleanv(GL_STEREO, &supports_stereo_quad_buffer);
if (supports_stereo_quad_buffer) {
front_right = new GLFrameBuffer("front_right", this, GL_FRONT_RIGHT, 0, w, h);
back_right = new GLFrameBuffer("back_right", this, GL_BACK_RIGHT, 0, w, h);
@@ -151,16 +152,35 @@ void GLContext::activate(void)
/* Not really following the state but we should consider
* no ubo bound when activating a context. */
bound_ubo_slots = 0;
+
+ immActivate();
}
void GLContext::deactivate(void)
{
+ immDeactivate();
is_active_ = false;
}
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Flush, Finish & sync
+ * \{ */
+
+void GLContext::flush(void)
+{
+ glFlush();
+}
+
+void GLContext::finish(void)
+{
+ glFinish();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Safe object deletion
*
* GPU objects can be freed when the context is not bound.
@@ -170,7 +190,7 @@ void GLContext::deactivate(void)
void GLSharedOrphanLists::orphans_clear(void)
{
/* Check if any context is active on this thread! */
- BLI_assert(GPU_context_active_get());
+ BLI_assert(GLContext::get());
lists_mutex.lock();
if (!buffers.is_empty()) {
@@ -212,7 +232,7 @@ void GLContext::orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex,
void GLContext::vao_free(GLuint vao_id)
{
- if (this == GPU_context_active_get()) {
+ if (this == GLContext::get()) {
glDeleteVertexArrays(1, &vao_id);
}
else {
@@ -222,7 +242,7 @@ void GLContext::vao_free(GLuint vao_id)
void GLContext::fbo_free(GLuint fbo_id)
{
- if (this == GPU_context_active_get()) {
+ if (this == GLContext::get()) {
glDeleteFramebuffers(1, &fbo_id);
}
else {
@@ -230,25 +250,27 @@ void GLContext::fbo_free(GLuint fbo_id)
}
}
-void GLBackend::buf_free(GLuint buf_id)
+void GLContext::buf_free(GLuint buf_id)
{
/* Any context can free. */
- if (GPU_context_active_get()) {
+ if (GLContext::get()) {
glDeleteBuffers(1, &buf_id);
}
else {
- orphans_add(shared_orphan_list_.buffers, shared_orphan_list_.lists_mutex, buf_id);
+ GLSharedOrphanLists &orphan_list = GLBackend::get()->shared_orphan_list_get();
+ orphans_add(orphan_list.buffers, orphan_list.lists_mutex, buf_id);
}
}
-void GLBackend::tex_free(GLuint tex_id)
+void GLContext::tex_free(GLuint tex_id)
{
/* Any context can free. */
- if (GPU_context_active_get()) {
+ if (GLContext::get()) {
glDeleteTextures(1, &tex_id);
}
else {
- orphans_add(shared_orphan_list_.textures, shared_orphan_list_.lists_mutex, tex_id);
+ GLSharedOrphanLists &orphan_list = GLBackend::get()->shared_orphan_list_get();
+ orphans_add(orphan_list.textures, orphan_list.lists_mutex, tex_id);
}
}
@@ -277,3 +299,30 @@ void GLContext::vao_cache_unregister(GLVaoCache *cache)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Memory statistics
+ * \{ */
+
+void GLContext::memory_statistics_get(int *r_total_mem, int *r_free_mem)
+{
+ /* TODO(merwin): use Apple's platform API to get this info. */
+ if (GLEW_NVX_gpu_memory_info) {
+ /* Teturned value in Kb. */
+ glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, r_total_mem);
+ glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, r_free_mem);
+ }
+ else if (GLEW_ATI_meminfo) {
+ int stats[4];
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
+
+ *r_total_mem = 0;
+ *r_free_mem = stats[0]; /* Total memory free in the pool. */
+ }
+ else {
+ *r_total_mem = 0;
+ *r_free_mem = 0;
+ }
+}
+
+/** \} */
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index 9e6359fabad..10ae396d138 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -53,15 +53,29 @@ class GLSharedOrphanLists {
void orphans_clear(void);
};
-class GLContext : public GPUContext {
+class GLContext : public Context {
public:
- /** Used for debugging purpose. Bitflags of all bound slots. */
- uint16_t bound_ubo_slots;
+ /** Capabilities. */
+ static GLint max_texture_3d_size;
+ static GLint max_cubemap_size;
+ static GLint max_ubo_size;
+ static GLint max_ubo_binds;
+ /** Extensions. */
+ static bool base_instance_support;
+ static bool debug_layer_support;
+ static bool texture_cube_map_array_support;
+ /** Workarounds. */
+ static bool texture_copy_workaround;
+ static bool unused_fb_slot_workaround;
+ static float derivative_signs[2];
- /* TODO(fclem) these needs to become private. */
- public:
/** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */
GLuint default_attr_vbo_;
+
+ /** Used for debugging purpose. Bitflags of all bound slots. */
+ uint16_t bound_ubo_slots;
+
+ private:
/**
* GPUBatch & GPUFramebuffer have references to the context they are from, in the case the
* context is destroyed, we need to remove any reference to it.
@@ -85,21 +99,37 @@ class GLContext : public GPUContext {
void activate(void) override;
void deactivate(void) override;
- static inline GLStateManager *state_manager_active_get()
+ void flush(void) override;
+ void finish(void) override;
+
+ void memory_statistics_get(int *total_mem, int *free_mem) override;
+
+ static GLContext *get()
{
- GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
+ return static_cast<GLContext *>(Context::get());
+ }
+
+ static GLStateManager *state_manager_active_get()
+ {
+ GLContext *ctx = GLContext::get();
return static_cast<GLStateManager *>(ctx->state_manager);
};
- /* TODO(fclem) these needs to become private. */
- public:
- void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id);
- void orphans_clear(void);
-
+ /* These need to be called with the context the id was created with. */
void vao_free(GLuint vao_id);
void fbo_free(GLuint fbo_id);
+ /* These can be called by any threads even without OpenGL ctx. Deletion will be delayed. */
+ static void buf_free(GLuint buf_id);
+ static void tex_free(GLuint tex_id);
+
void vao_cache_register(GLVaoCache *cache);
void vao_cache_unregister(GLVaoCache *cache);
+
+ private:
+ static void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id);
+ void orphans_clear(void);
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("GLContext")
};
} // namespace gpu
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index d54ea0919b6..468d1514d60 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -122,7 +122,7 @@ void init_gl_callbacks(void)
char msg[256] = "";
const char format[] = "Successfully hooked OpenGL debug callback using %s";
- if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
+ if (GLContext::debug_layer_support) {
SNPRINTF(msg, format, GLEW_VERSION_4_3 ? "OpenGL 4.3" : "KHR_debug extension");
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -197,7 +197,7 @@ void check_gl_resources(const char *info)
return;
}
- GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
+ GLContext *ctx = GLContext::get();
ShaderInterface *interface = ctx->shader->interface;
/* NOTE: This only check binding. To be valid, the bound ubo needs to
* be big enough to feed the data range the shader awaits. */
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
index d8c17084457..6e3b1107b9c 100644
--- a/source/blender/gpu/opengl/gl_drawlist.cc
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -27,7 +27,7 @@
#include "BLI_assert.h"
#include "GPU_batch.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "glew-mx.h"
@@ -76,7 +76,7 @@ GLDrawList::GLDrawList(int length)
data_ = NULL;
if (USE_MULTI_DRAW_INDIRECT && GLEW_ARB_multi_draw_indirect &&
- GPU_arb_base_instance_is_supported()) {
+ GLContext::base_instance_support) {
/* Alloc the biggest possible command list, which is indexed. */
buffer_size_ = sizeof(GLDrawCommandIndexed) * length;
}
@@ -88,15 +88,12 @@ GLDrawList::GLDrawList(int length)
GLDrawList::~GLDrawList()
{
- /* TODO This ... */
- static_cast<GLBackend *>(GPUBackend::get())->buf_free(buffer_id_);
- /* ... should be this. */
- // context_->buf_free(buffer_id_)
+ GLContext::buf_free(buffer_id_);
}
void GLDrawList::init(void)
{
- BLI_assert(GPU_context_active_get());
+ BLI_assert(GLContext::get());
BLI_assert(MDI_ENABLED);
BLI_assert(data_ == NULL);
batch_ = NULL;
@@ -105,7 +102,7 @@ void GLDrawList::init(void)
if (buffer_id_ == 0) {
/* Allocate on first use. */
glGenBuffers(1, &buffer_id_);
- context_ = static_cast<GLContext *>(GPU_context_active_get());
+ context_ = GLContext::get();
}
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer_id_);
@@ -183,7 +180,7 @@ void GLDrawList::submit(void)
/* Something's wrong if we get here without MDI support. */
BLI_assert(MDI_ENABLED);
BLI_assert(data_);
- BLI_assert(GPU_context_active_get()->shader != NULL);
+ BLI_assert(GLContext::get()->shader != NULL);
/* Only do multi-draw indirect if doing more than 2 drawcall. This avoids the overhead of
* buffer mapping if scene is not very instance friendly. BUT we also need to take into
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 4be471b236a..bfc8a2f74eb 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -23,7 +23,7 @@
#include "BKE_global.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "gl_backend.hh"
#include "gl_framebuffer.hh"
@@ -63,13 +63,11 @@ GLFrameBuffer::GLFrameBuffer(
viewport_[2] = scissor_[2] = w;
viewport_[3] = scissor_[3] = h;
-#ifndef __APPLE__
- if (fbo_id_ && (G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (fbo_id_ && GLContext::debug_layer_support) {
char sh_name[32];
SNPRINTF(sh_name, "FrameBuffer-%s", name);
glObjectLabel(GL_FRAMEBUFFER, fbo_id_, -1, sh_name);
}
-#endif
}
GLFrameBuffer::~GLFrameBuffer()
@@ -78,8 +76,8 @@ GLFrameBuffer::~GLFrameBuffer()
return;
}
- if (context_ == GPU_context_active_get()) {
- /* Context might be partially freed. This happens when destroying the window frame-buffers. */
+ /* Context might be partially freed. This happens when destroying the window frame-buffers. */
+ if (context_ == Context::get()) {
glDeleteFramebuffers(1, &fbo_id_);
}
else {
@@ -89,26 +87,24 @@ GLFrameBuffer::~GLFrameBuffer()
if (context_->active_fb == this && context_->back_left != this) {
/* If this assert triggers it means the frame-buffer is being freed while in use by another
* context which, by the way, is TOTALLY UNSAFE!!! */
- BLI_assert(context_ == GPU_context_active_get());
+ BLI_assert(context_ == Context::get());
GPU_framebuffer_restore();
}
}
void GLFrameBuffer::init(void)
{
- context_ = static_cast<GLContext *>(GPU_context_active_get());
+ context_ = GLContext::get();
state_manager_ = static_cast<GLStateManager *>(context_->state_manager);
glGenFramebuffers(1, &fbo_id_);
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
char sh_name[64];
SNPRINTF(sh_name, "FrameBuffer-%s", name_);
/* Binding before setting the label is needed on some drivers. */
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
glObjectLabel(GL_FRAMEBUFFER, fbo_id_, -1, sh_name);
}
-#endif
}
/** \} */
@@ -187,7 +183,7 @@ void GLFrameBuffer::update_attachments(void)
glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
continue;
}
- GLuint gl_tex = GPU_texture_opengl_bindcode(attach.tex);
+ GLuint gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
if (attach.layer > -1 && GPU_texture_cube(attach.tex) && !GPU_texture_array(attach.tex)) {
/* Could be avoided if ARB_direct_state_access is required. In this case
* #glFramebufferTextureLayer would bind the correct face. */
@@ -208,7 +204,7 @@ void GLFrameBuffer::update_attachments(void)
}
}
- if (GPU_unused_fb_slot_workaround()) {
+ if (GLContext::unused_fb_slot_workaround) {
/* Fill normally un-occupied slots to avoid rendering artifacts on some hardware. */
GLuint gl_tex = 0;
/* NOTE: Inverse iteration to get the first color texture. */
@@ -216,7 +212,7 @@ void GLFrameBuffer::update_attachments(void)
GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0 + i;
GPUAttachment &attach = attachments_[type];
if (attach.tex != NULL) {
- gl_tex = GPU_texture_opengl_bindcode(attach.tex);
+ gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
}
else if (gl_tex != 0) {
GLenum gl_attachment = to_gl(type);
@@ -274,7 +270,7 @@ void GLFrameBuffer::bind(bool enabled_srgb)
this->init();
}
- if (context_ != GPU_context_active_get()) {
+ if (context_ != GLContext::get()) {
BLI_assert(!"Trying to use the same frame-buffer in multiple context");
return;
}
@@ -320,7 +316,7 @@ void GLFrameBuffer::clear(eGPUFrameBufferBits buffers,
float clear_depth,
uint clear_stencil)
{
- BLI_assert(GPU_context_active_get() == context_);
+ BLI_assert(GLContext::get() == context_);
BLI_assert(context_->active_fb == this);
/* Save and restore the state. */
@@ -360,7 +356,7 @@ void GLFrameBuffer::clear_attachment(GPUAttachmentType type,
eGPUDataFormat data_format,
const void *clear_value)
{
- BLI_assert(GPU_context_active_get() == context_);
+ BLI_assert(GLContext::get() == context_);
BLI_assert(context_->active_fb == this);
/* Save and restore the state. */
diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh
index 73423425500..755f3f97567 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.hh
+++ b/source/blender/gpu/opengl/gl_framebuffer.hh
@@ -63,13 +63,13 @@ class GLFrameBuffer : public FrameBuffer {
GLFrameBuffer(const char *name);
/**
- * Special Framebuffer encapsulating internal window framebuffer.
- * (i.e.: GL_FRONT_LEFT, GL_BACK_RIGHT, ...)
- * @param ctx context the handle is from.
- * @param target the internal GL name (i.e: GL_BACK_LEFT).
- * @param fbo the (optional) already created object for some implementation. Default is 0.
- * @param w buffer width.
- * @param h buffer height.
+ * Special frame-buffer encapsulating internal window frame-buffer.
+ * (i.e.: #GL_FRONT_LEFT, #GL_BACK_RIGHT, ...)
+ * \param ctx: context the handle is from.
+ * \param target: the internal GL name (i.e: #GL_BACK_LEFT).
+ * \param fbo: the (optional) already created object for some implementation. Default is 0.
+ * \param w: buffer width.
+ * \param h: buffer height.
**/
GLFrameBuffer(const char *name, GLContext *ctx, GLenum target, GLuint fbo, int w, int h);
diff --git a/source/blender/gpu/opengl/gl_immediate.cc b/source/blender/gpu/opengl/gl_immediate.cc
index 7f12f41a598..7afbbf9965c 100644
--- a/source/blender/gpu/opengl/gl_immediate.cc
+++ b/source/blender/gpu/opengl/gl_immediate.cc
@@ -60,13 +60,11 @@ GLImmediate::GLImmediate()
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
glObjectLabel(GL_VERTEX_ARRAY, vao_id_, -1, "VAO-Immediate");
glObjectLabel(GL_BUFFER, buffer.vbo_id, -1, "VBO-ImmediateBuffer");
glObjectLabel(GL_BUFFER, buffer_strict.vbo_id, -1, "VBO-ImmediateBufferStrict");
}
-#endif
}
GLImmediate::~GLImmediate()
@@ -160,7 +158,7 @@ void GLImmediate::end(void)
GL_CHECK_ERROR("Immediate Post-Unmap");
if (vertex_len > 0) {
- GPU_context_active_get()->state_manager->apply_state();
+ GLContext::get()->state_manager->apply_state();
/* We convert the offset in vertex offset from the buffer's start.
* This works because we added some padding to align the first vertex vertex. */
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index 03a9607a00b..d68953e6daa 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -21,7 +21,7 @@
* \ingroup gpu
*/
-#include "gl_backend.hh"
+#include "gl_context.hh"
#include "gl_debug.hh"
#include "gl_index_buffer.hh"
@@ -30,7 +30,7 @@ namespace blender::gpu {
GLIndexBuf::~GLIndexBuf()
{
- GLBackend::get()->buf_free(ibo_id_);
+ GLContext::buf_free(ibo_id_);
}
void GLIndexBuf::bind(void)
diff --git a/source/blender/gpu/opengl/gl_query.cc b/source/blender/gpu/opengl/gl_query.cc
new file mode 100644
index 00000000000..6da5cacfcb2
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_query.cc
@@ -0,0 +1,78 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gl_query.hh"
+
+namespace blender::gpu {
+
+#define QUERY_CHUNCK_LEN 256
+
+GLQueryPool::~GLQueryPool()
+{
+ glDeleteQueries(query_ids_.size(), query_ids_.data());
+}
+
+void GLQueryPool::init(GPUQueryType type)
+{
+ BLI_assert(initialized_ == false);
+ initialized_ = true;
+ type_ = type;
+ gl_type_ = to_gl(type);
+ query_issued_ = 0;
+}
+
+#if 0 /* TODO to avoid realloc of permanent query pool. */
+void GLQueryPool::reset(GPUQueryType type)
+{
+ initialized_ = false;
+}
+#endif
+
+void GLQueryPool::begin_query(void)
+{
+ /* TODO add assert about expected usage. */
+ while (query_issued_ >= query_ids_.size()) {
+ int64_t prev_size = query_ids_.size();
+ query_ids_.resize(prev_size + QUERY_CHUNCK_LEN);
+ glGenQueries(QUERY_CHUNCK_LEN, &query_ids_[prev_size]);
+ }
+ glBeginQuery(gl_type_, query_ids_[query_issued_++]);
+}
+
+void GLQueryPool::end_query(void)
+{
+ /* TODO add assert about expected usage. */
+ glEndQuery(gl_type_);
+}
+
+void GLQueryPool::get_occlusion_result(MutableSpan<uint32_t> r_values)
+{
+ BLI_assert(r_values.size() == query_issued_);
+
+ for (int i = 0; i < query_issued_; i++) {
+ /* Note: This is a sync point. */
+ glGetQueryObjectuiv(query_ids_[i], GL_QUERY_RESULT, &r_values[i]);
+ }
+}
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_query.hh b/source/blender/gpu/opengl/gl_query.hh
new file mode 100644
index 00000000000..fc54c0ee1dd
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_query.hh
@@ -0,0 +1,69 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_vector.hh"
+
+#include "gpu_query.hh"
+
+#include "glew-mx.h"
+
+namespace blender::gpu {
+
+class GLQueryPool : public QueryPool {
+ private:
+ /** Contains queries object handles. */
+ Vector<GLuint> query_ids_;
+ /** Type of this query pool. */
+ GPUQueryType type_;
+ /** Associated GL type. */
+ GLenum gl_type_;
+ /** Number of queries that have been issued since last initialization.
+ * Should be equal to query_ids_.size(). */
+ uint32_t query_issued_;
+ /** Can only be initialized once. */
+ bool initialized_ = false;
+
+ public:
+ ~GLQueryPool();
+
+ void init(GPUQueryType type) override;
+
+ void begin_query(void) override;
+ void end_query(void) override;
+
+ void get_occlusion_result(MutableSpan<uint32_t> r_values) override;
+};
+
+static inline GLenum to_gl(GPUQueryType type)
+{
+ if (type == GPU_QUERY_OCCLUSION) {
+ /* TODO(fclem) try with GL_ANY_SAMPLES_PASSED​. */
+ return GL_SAMPLES_PASSED;
+ }
+ BLI_assert(0);
+ return GL_SAMPLES_PASSED;
+}
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 9136a1d9714..4314ecfa6be 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -25,9 +25,9 @@
#include "BLI_string.h"
-#include "GPU_extensions.h"
#include "GPU_platform.h"
+#include "gl_backend.hh"
#include "gl_vertex_buffer.hh"
#include "gl_shader.hh"
@@ -44,24 +44,22 @@ GLShader::GLShader(const char *name) : Shader(name)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GPU_context_active_get() != NULL);
+ BLI_assert(GLContext::get() != NULL);
#endif
shader_program_ = glCreateProgram();
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
char sh_name[64];
SNPRINTF(sh_name, "ShaderProgram-%s", name);
glObjectLabel(GL_PROGRAM, shader_program_, -1, sh_name);
}
-#endif
}
GLShader::~GLShader(void)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GPU_context_active_get() != NULL);
+ BLI_assert(GLContext::get() != NULL);
#endif
/* Invalid handles are silently ignored. */
glDeleteShader(vert_shader_);
@@ -112,16 +110,14 @@ char *GLShader::glsl_patch_get(void)
STR_CONCAT(patch, slen, "#extension GL_ARB_shader_draw_parameters : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_shader_draw_parameters\n");
}
- if (GPU_arb_texture_cube_map_array_is_supported()) {
+ if (GLContext::texture_cube_map_array_support) {
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
}
/* Derivative sign can change depending on implementation. */
- float derivatives[2];
- GPU_get_dfdy_factors(derivatives);
- STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", derivatives[0]);
- STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", derivatives[1]);
+ STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]);
+ STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]);
BLI_assert(slen < sizeof(patch));
return patch;
@@ -167,8 +163,7 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *>
return 0;
}
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
char sh_name[64];
switch (gl_stage) {
case GL_VERTEX_SHADER:
@@ -183,7 +178,6 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *>
}
glObjectLabel(GL_SHADER, shader, -1, sh_name);
}
-#endif
glAttachShader(shader_program_, shader);
return shader;
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index dc6d475d39f..6dcb56288e8 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -25,7 +25,7 @@
#include "BLI_math_base.h"
#include "BLI_math_bits.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "glew-mx.h"
@@ -520,6 +520,11 @@ void GLStateManager::texture_bind_apply(void)
}
}
+void GLStateManager::texture_unpack_row_length_set(uint len)
+{
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, len);
+}
+
uint64_t GLStateManager::bound_texture_slots(void)
{
uint64_t bound_slots = 0;
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index d5622b4ab89..db9b9721ad5 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -74,6 +74,8 @@ class GLStateManager : public GPUStateManager {
void texture_unbind(Texture *tex) override;
void texture_unbind_all(void) override;
+ void texture_unpack_row_length_set(uint len) override;
+
uint64_t bound_texture_slots(void);
private:
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index 6cff97215e8..ec08b736af2 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -25,7 +25,7 @@
#include "DNA_userdef_types.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_platform.h"
@@ -44,7 +44,7 @@ namespace blender::gpu {
GLTexture::GLTexture(const char *name) : Texture(name)
{
- BLI_assert(GPU_context_active_get() != NULL);
+ BLI_assert(GLContext::get() != NULL);
glGenTextures(1, &tex_id_);
}
@@ -54,12 +54,12 @@ GLTexture::~GLTexture()
if (framebuffer_) {
GPU_framebuffer_free(framebuffer_);
}
- GPUContext *ctx = GPU_context_active_get();
+ GLContext *ctx = GLContext::get();
if (ctx != NULL && is_bound_) {
/* This avoid errors when the texture is still inside the bound texture array. */
ctx->state_manager->texture_unbind(this);
}
- GLBackend::get()->tex_free(tex_id_);
+ GLContext::tex_free(tex_id_);
}
/* Return true on success. */
@@ -71,8 +71,9 @@ bool GLTexture::init_internal(void)
format_ = GPU_DEPTH32F_STENCIL8;
}
- if ((type_ == GPU_TEXTURE_CUBE_ARRAY) && !GPU_arb_texture_cube_map_array_is_supported()) {
- debug::raise_gl_error("Attempt to create a cubemap array without hardware support!");
+ if ((type_ == GPU_TEXTURE_CUBE_ARRAY) && (GLContext::texture_cube_map_array_support == false)) {
+ /* Silently fail and let the caller handle the error. */
+ // debug::raise_gl_error("Attempt to create a cubemap array without hardware support!");
return false;
}
@@ -95,14 +96,12 @@ bool GLTexture::init_internal(void)
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
char sh_name[64];
SNPRINTF(sh_name, "Texture-%s", name_);
/* Binding before setting the label is needed on some drivers. */
glObjectLabel(GL_TEXTURE, tex_id_, -1, sh_name);
}
-#endif
GL_CHECK_ERROR("Post-texture creation");
return true;
@@ -126,14 +125,12 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
glTexBuffer(target_, internal_format, gl_vbo->vbo_id_);
}
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
char sh_name[64];
SNPRINTF(sh_name, "Texture-%s", name_);
/* Binding before setting the label is needed on some drivers. */
glObjectLabel(GL_TEXTURE, tex_id_, -1, sh_name);
}
-#endif
GL_CHECK_ERROR("Post-texture buffer creation");
return true;
@@ -369,7 +366,7 @@ void GLTexture::copy_to(Texture *dst_)
/* TODO support array / 3D textures. */
BLI_assert(dst->d_ == 0);
- if (GLEW_ARB_copy_image && !GPU_texture_copy_workaround()) {
+ if (GLEW_ARB_copy_image && !GLContext::texture_copy_workaround) {
/* Opengl 4.3 */
int mip = 0;
/* NOTE: mip_size_get() won't override any dimension that is equal to 0. */
@@ -512,6 +509,23 @@ void GLTexture::samplers_init(void)
* - GL_TEXTURE_MAX_LOD is 1000.
* - GL_TEXTURE_LOD_BIAS is 0.0f.
**/
+
+ if (GLContext::debug_layer_support) {
+ char sampler_name[128];
+ SNPRINTF(sampler_name,
+ "Sampler%s%s%s%s%s%s%s%s%s%s",
+ (state == GPU_SAMPLER_DEFAULT) ? "_default" : "",
+ (state & GPU_SAMPLER_FILTER) ? "_filter" : "",
+ (state & GPU_SAMPLER_MIPMAP) ? "_mipmap" : "",
+ (state & GPU_SAMPLER_REPEAT) ? "_repeat-" : "",
+ (state & GPU_SAMPLER_REPEAT_S) ? "S" : "",
+ (state & GPU_SAMPLER_REPEAT_T) ? "T" : "",
+ (state & GPU_SAMPLER_REPEAT_R) ? "R" : "",
+ (state & GPU_SAMPLER_CLAMP_BORDER) ? "_clamp_border" : "",
+ (state & GPU_SAMPLER_COMPARE) ? "_compare" : "",
+ (state & GPU_SAMPLER_ANISO) ? "_aniso" : "");
+ glObjectLabel(GL_SAMPLER, samplers_[i], -1, sampler_name);
+ }
}
samplers_update();
@@ -520,6 +534,10 @@ void GLTexture::samplers_init(void)
glSamplerParameteri(icon_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(icon_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameterf(icon_sampler, GL_TEXTURE_LOD_BIAS, -0.5f);
+
+ if (GLContext::debug_layer_support) {
+ glObjectLabel(GL_SAMPLER, icon_sampler, -1, "Sampler-icons");
+ }
}
void GLTexture::samplers_update(void)
@@ -560,8 +578,8 @@ bool GLTexture::proxy_check(int mip)
{
/* Manual validation first, since some implementation have issues with proxy creation. */
int max_size = GPU_max_texture_size();
- int max_3d_size = GPU_max_texture_3d_size();
- int max_cube_size = GPU_max_cube_map_size();
+ int max_3d_size = GLContext::max_texture_3d_size;
+ int max_cube_size = GLContext::max_cubemap_size;
int size[3] = {1, 1, 1};
this->mip_size_get(mip, size);
@@ -661,7 +679,7 @@ void GLTexture::check_feedback_loop(void)
if (GPU_mip_render_workaround()) {
return;
}
- GLFrameBuffer *fb = static_cast<GLFrameBuffer *>(GPU_context_active_get()->active_fb);
+ GLFrameBuffer *fb = static_cast<GLFrameBuffer *>(GLContext::get()->active_fb);
for (int i = 0; i < ARRAY_SIZE(fb_); i++) {
if (fb_[i] == fb) {
GPUAttachmentType type = fb_attachment_[i];
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index bdb8a4df4b7..13e546eb879 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -46,6 +46,7 @@ namespace gpu {
class GLTexture : public Texture {
friend class GLStateManager;
+ friend class GLFrameBuffer;
private:
/** All samplers states. */
diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.cc b/source/blender/gpu/opengl/gl_uniform_buffer.cc
index 0e0c64e5c60..74453a08bfe 100644
--- a/source/blender/gpu/opengl/gl_uniform_buffer.cc
+++ b/source/blender/gpu/opengl/gl_uniform_buffer.cc
@@ -25,8 +25,6 @@
#include "BLI_string.h"
-#include "GPU_extensions.h"
-
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
@@ -42,11 +40,12 @@ namespace blender::gpu {
GLUniformBuf::GLUniformBuf(size_t size, const char *name) : UniformBuf(size, name)
{
/* Do not create ubo GL buffer here to allow allocation from any thread. */
+ BLI_assert(size <= GLContext::max_ubo_size);
}
GLUniformBuf::~GLUniformBuf()
{
- GLBackend::get()->buf_free(ubo_id_);
+ GLContext::buf_free(ubo_id_);
}
/** \} */
@@ -57,19 +56,17 @@ GLUniformBuf::~GLUniformBuf()
void GLUniformBuf::init(void)
{
- BLI_assert(GPU_context_active_get());
+ BLI_assert(GLContext::get());
glGenBuffers(1, &ubo_id_);
glBindBuffer(GL_UNIFORM_BUFFER, ubo_id_);
glBufferData(GL_UNIFORM_BUFFER, size_in_bytes_, NULL, GL_DYNAMIC_DRAW);
-#ifndef __APPLE__
- if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
+ if (GLContext::debug_layer_support) {
char sh_name[64];
SNPRINTF(sh_name, "UBO-%s", name_);
glObjectLabel(GL_BUFFER, ubo_id_, -1, sh_name);
}
-#endif
}
void GLUniformBuf::update(const void *data)
@@ -90,12 +87,12 @@ void GLUniformBuf::update(const void *data)
void GLUniformBuf::bind(int slot)
{
- if (slot >= GPU_max_ubo_binds()) {
+ if (slot >= GLContext::max_ubo_binds) {
fprintf(stderr,
"Error: Trying to bind \"%s\" ubo to slot %d which is above the reported limit of %d.",
name_,
slot,
- GPU_max_ubo_binds());
+ GLContext::max_ubo_binds);
return;
}
@@ -113,7 +110,7 @@ void GLUniformBuf::bind(int slot)
#ifdef DEBUG
BLI_assert(slot < 16);
- static_cast<GLContext *>(GPU_context_active_get())->bound_ubo_slots |= 1 << slot;
+ GLContext::get()->bound_ubo_slots |= 1 << slot;
#endif
}
@@ -123,7 +120,7 @@ void GLUniformBuf::unbind(void)
/* NOTE: This only unbinds the last bound slot. */
glBindBufferBase(GL_UNIFORM_BUFFER, slot_, 0);
/* Hope that the context did not change. */
- static_cast<GLContext *>(GPU_context_active_get())->bound_ubo_slots &= ~(1 << slot_);
+ GLContext::get()->bound_ubo_slots &= ~(1 << slot_);
#endif
slot_ = 0;
}
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index 4e49828d39d..732221cfab3 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -138,7 +138,7 @@ void GLVertArray::update_bindings(const GLuint vao,
if (attr_mask != 0 && GLEW_ARB_vertex_attrib_binding) {
for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) {
if (attr_mask & mask) {
- GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
+ GLContext *ctx = GLContext::get();
/* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style.
* Fix issues for some drivers (see T75069). */
glBindVertexBuffer(a, ctx->default_attr_vbo_, (intptr_t)0, (intptr_t)0);
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc
index 66ff1f36cef..a724c94775e 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.cc
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc
@@ -21,7 +21,7 @@
* \ingroup gpu
*/
-#include "gl_backend.hh"
+#include "gl_context.hh"
#include "gl_vertex_buffer.hh"
@@ -42,7 +42,7 @@ void GLVertBuf::resize_data(void)
void GLVertBuf::release_data(void)
{
if (vbo_id_ != 0) {
- GLBackend::get()->buf_free(vbo_id_);
+ GLContext::buf_free(vbo_id_);
vbo_id_ = 0;
memory_usage -= vbo_size_;
}
@@ -52,7 +52,7 @@ void GLVertBuf::release_data(void)
void GLVertBuf::duplicate_data(VertBuf *dst_)
{
- BLI_assert(GPU_context_active_get() != NULL);
+ BLI_assert(GLContext::get() != NULL);
GLVertBuf *src = this;
GLVertBuf *dst = static_cast<GLVertBuf *>(dst_);
@@ -82,7 +82,7 @@ void GLVertBuf::upload_data(void)
void GLVertBuf::bind(void)
{
- BLI_assert(GPU_context_active_get() != NULL);
+ BLI_assert(GLContext::get() != NULL);
if (vbo_id_ == 0) {
glGenBuffers(1, &vbo_id_);
diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc
new file mode 100644
index 00000000000..2772139b8f6
--- /dev/null
+++ b/source/blender/gpu/tests/gpu_testing.cc
@@ -0,0 +1,31 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "GPU_context.h"
+#include "GPU_init_exit.h"
+#include "gpu_testing.hh"
+
+#include "GHOST_C-api.h"
+
+namespace blender::gpu {
+
+void GPUTest::SetUp()
+{
+ GHOST_GLSettings glSettings = {0};
+ ghost_system = GHOST_CreateSystem();
+ ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings);
+ context = GPU_context_create(NULL);
+ GPU_init();
+}
+
+void GPUTest::TearDown()
+{
+ GPU_exit();
+ GPU_backend_exit();
+ GPU_context_discard(context);
+ GHOST_DisposeOpenGLContext(ghost_system, ghost_context);
+ GHOST_DisposeSystem(ghost_system);
+}
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/gpu/tests/gpu_testing.hh b/source/blender/gpu/tests/gpu_testing.hh
new file mode 100644
index 00000000000..7e9203d2d7c
--- /dev/null
+++ b/source/blender/gpu/tests/gpu_testing.hh
@@ -0,0 +1,27 @@
+#include "testing/testing.h"
+
+#include "GHOST_C-api.h"
+
+struct GPUContext;
+
+namespace blender::gpu {
+
+/* Test class that setups a GPUContext for test cases.
+ *
+ * Usage:
+ * TEST_F(GPUTest, my_gpu_test) {
+ * ...
+ * }
+ */
+class GPUTest : public ::testing::Test {
+ private:
+ GHOST_SystemHandle ghost_system;
+ GHOST_ContextHandle ghost_context;
+ struct GPUContext *context;
+
+ protected:
+ void SetUp() override;
+ void TearDown() override;
+};
+
+} // namespace blender::gpu \ No newline at end of file
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 73532a1825e..2826bd63cc1 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -30,7 +30,7 @@
#include "BKE_global.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_texture.h"
#include "IMB_colormanagement.h"
diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h
index 28e3d0dd1f5..9a2c74c64a3 100644
--- a/source/blender/io/alembic/ABC_alembic.h
+++ b/source/blender/io/alembic/ABC_alembic.h
@@ -60,6 +60,7 @@ struct AlembicExportParams {
bool triangulate;
bool export_hair;
bool export_particles;
+ bool use_instancing;
/* See MOD_TRIANGULATE_NGON_xxx and MOD_TRIANGULATE_QUAD_xxx
* in DNA_modifier_types.h */
diff --git a/source/blender/io/alembic/CMakeLists.txt b/source/blender/io/alembic/CMakeLists.txt
index de99a2c9d65..2b44146e475 100644
--- a/source/blender/io/alembic/CMakeLists.txt
+++ b/source/blender/io/alembic/CMakeLists.txt
@@ -63,6 +63,7 @@ set(SRC
exporter/abc_writer_camera.cc
exporter/abc_writer_curves.cc
exporter/abc_writer_hair.cc
+ exporter/abc_writer_instance.cc
exporter/abc_writer_mball.cc
exporter/abc_writer_mesh.cc
exporter/abc_writer_nurbs.cc
@@ -89,6 +90,7 @@ set(SRC
exporter/abc_writer_camera.h
exporter/abc_writer_curves.h
exporter/abc_writer_hair.h
+ exporter/abc_writer_instance.h
exporter/abc_writer_mball.h
exporter/abc_writer_mesh.h
exporter/abc_writer_nurbs.h
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
index 5b1b1b60b48..4cb6ca0c601 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
@@ -22,6 +22,7 @@
#include "abc_writer_camera.h"
#include "abc_writer_curves.h"
#include "abc_writer_hair.h"
+#include "abc_writer_instance.h"
#include "abc_writer_mball.h"
#include "abc_writer_mesh.h"
#include "abc_writer_nurbs.h"
@@ -126,17 +127,27 @@ AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator::determine
context, dupli_object, dupli_parent_finder);
}
-Alembic::Abc::OObject ABCHierarchyIterator::get_alembic_parent(
- const HierarchyContext *context) const
+Alembic::Abc::OObject ABCHierarchyIterator::get_alembic_object(
+ const std::string &export_path) const
{
- Alembic::Abc::OObject parent;
+ if (export_path.empty()) {
+ return Alembic::Abc::OObject();
+ }
- if (!context->higher_up_export_path.empty()) {
- AbstractHierarchyWriter *writer = get_writer(context->higher_up_export_path);
- ABCAbstractWriter *abc_writer = static_cast<ABCAbstractWriter *>(writer);
- parent = abc_writer->get_alembic_object();
+ AbstractHierarchyWriter *writer = get_writer(export_path);
+ if (writer == nullptr) {
+ return Alembic::Abc::OObject();
}
+ ABCAbstractWriter *abc_writer = static_cast<ABCAbstractWriter *>(writer);
+ return abc_writer->get_alembic_object();
+}
+
+Alembic::Abc::OObject ABCHierarchyIterator::get_alembic_parent(
+ const HierarchyContext *context) const
+{
+ Alembic::Abc::OObject parent = get_alembic_object(context->higher_up_export_path);
+
if (!parent.valid()) {
/* An invalid parent object means "no parent", which should be translated to Alembic's top
* archive object. */
@@ -173,32 +184,42 @@ AbstractHierarchyWriter *ABCHierarchyIterator::create_data_writer(const Hierarch
const ABCWriterConstructorArgs writer_args = writer_constructor_args(context);
ABCAbstractWriter *data_writer = nullptr;
+ if (params_.use_instancing && context->is_instance()) {
+ data_writer = new ABCInstanceWriter(writer_args);
+ }
+ else {
+ data_writer = create_data_writer_for_object_type(context, writer_args);
+ }
+
+ if (data_writer == nullptr || !data_writer->is_supported(context)) {
+ delete data_writer;
+ return nullptr;
+ }
+
+ data_writer->create_alembic_objects(context);
+ return data_writer;
+}
+
+ABCAbstractWriter *ABCHierarchyIterator::create_data_writer_for_object_type(
+ const HierarchyContext *context, const ABCWriterConstructorArgs &writer_args)
+{
switch (context->object->type) {
case OB_MESH:
- data_writer = new ABCMeshWriter(writer_args);
- break;
+ return new ABCMeshWriter(writer_args);
case OB_CAMERA:
- data_writer = new ABCCameraWriter(writer_args);
- break;
+ return new ABCCameraWriter(writer_args);
case OB_CURVE:
if (params_.curves_as_mesh) {
- data_writer = new ABCCurveMeshWriter(writer_args);
- }
- else {
- data_writer = new ABCCurveWriter(writer_args);
+ return new ABCCurveMeshWriter(writer_args);
}
- break;
+ return new ABCCurveWriter(writer_args);
case OB_SURF:
if (params_.curves_as_mesh) {
- data_writer = new ABCCurveMeshWriter(writer_args);
+ return new ABCCurveMeshWriter(writer_args);
}
- else {
- data_writer = new ABCNurbsWriter(writer_args);
- }
- break;
+ return new ABCNurbsWriter(writer_args);
case OB_MBALL:
- data_writer = new ABCMetaballWriter(writer_args);
- break;
+ return new ABCMetaballWriter(writer_args);
case OB_EMPTY:
case OB_LAMP:
@@ -214,13 +235,8 @@ AbstractHierarchyWriter *ABCHierarchyIterator::create_data_writer(const Hierarch
return nullptr;
}
- if (!data_writer->is_supported(context)) {
- delete data_writer;
- return nullptr;
- }
-
- data_writer->create_alembic_objects(context);
- return data_writer;
+ /* Just to please the compiler, all cases should be handled by the above switch. */
+ return nullptr;
}
AbstractHierarchyWriter *ABCHierarchyIterator::create_hair_writer(const HierarchyContext *context)
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
index bd7e3f27c67..5bc82564cdb 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
@@ -36,6 +36,7 @@ namespace blender {
namespace io {
namespace alembic {
+class ABCAbstractWriter;
class ABCHierarchyIterator;
struct ABCWriterConstructorArgs {
@@ -61,6 +62,8 @@ class ABCHierarchyIterator : public AbstractHierarchyIterator {
virtual void iterate_and_write() override;
virtual std::string make_valid_name(const std::string &name) const override;
+ Alembic::Abc::OObject get_alembic_object(const std::string &export_path) const;
+
protected:
virtual bool mark_as_weak_export(const Object *object) const override;
@@ -85,6 +88,9 @@ class ABCHierarchyIterator : public AbstractHierarchyIterator {
ABCWriterConstructorArgs writer_constructor_args(const HierarchyContext *context) const;
void update_archive_bounding_box();
void update_bounding_box_recursive(Imath::Box3d &bounds, const HierarchyContext *context);
+
+ ABCAbstractWriter *create_data_writer_for_object_type(
+ const HierarchyContext *context, const ABCWriterConstructorArgs &writer_args);
};
} // namespace alembic
diff --git a/source/blender/io/alembic/exporter/abc_writer_instance.cc b/source/blender/io/alembic/exporter/abc_writer_instance.cc
new file mode 100644
index 00000000000..581d94ee961
--- /dev/null
+++ b/source/blender/io/alembic/exporter/abc_writer_instance.cc
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup balembic
+ */
+
+#include "abc_writer_instance.h"
+#include "abc_hierarchy_iterator.h"
+
+#include "BLI_assert.h"
+
+#include "CLG_log.h"
+static CLG_LogRef LOG = {"io.alembic"};
+
+namespace blender {
+namespace io {
+namespace alembic {
+
+using Alembic::Abc::OObject;
+
+ABCInstanceWriter::ABCInstanceWriter(const ABCWriterConstructorArgs &args)
+ : ABCAbstractWriter(args)
+{
+}
+
+ABCInstanceWriter::~ABCInstanceWriter()
+{
+}
+
+void ABCInstanceWriter::create_alembic_objects(const HierarchyContext *context)
+{
+ OObject original = args_.hierarchy_iterator->get_alembic_object(context->original_export_path);
+ OObject abc_parent = args_.abc_parent;
+ if (!abc_parent.addChildInstance(original, args_.abc_name)) {
+ CLOG_WARN(&LOG, "unable to export %s as instance", args_.abc_path.c_str());
+ return;
+ }
+ CLOG_INFO(&LOG, 2, "exporting instance %s", args_.abc_path.c_str());
+}
+
+OObject ABCInstanceWriter::get_alembic_object() const
+{
+ /* There is no OObject for an instance. */
+ BLI_assert(!"ABCInstanceWriter cannot return its Alembic OObject");
+ return OObject();
+}
+
+bool ABCInstanceWriter::is_supported(const HierarchyContext *context) const
+{
+ return context->is_instance();
+}
+
+void ABCInstanceWriter::do_write(HierarchyContext & /*context*/)
+{
+ /* Instances don't have data to be written. Just creating them is enough. */
+}
+
+} // namespace alembic
+} // namespace io
+} // namespace blender
diff --git a/source/blender/io/alembic/exporter/abc_writer_instance.h b/source/blender/io/alembic/exporter/abc_writer_instance.h
new file mode 100644
index 00000000000..74379b9d6bd
--- /dev/null
+++ b/source/blender/io/alembic/exporter/abc_writer_instance.h
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#pragma once
+
+/** \file
+ * \ingroup balembic
+ */
+
+#include "abc_writer_abstract.h"
+
+namespace blender {
+namespace io {
+namespace alembic {
+
+/* Writer for Alembic instances, i.e. data that references another Alembic object.
+ *
+ * Note that the Alembic object created by this writer cannot be used as a
+ * parent, because it already instantiates the entire hierarchy of the
+ * referenced object. */
+class ABCInstanceWriter : public ABCAbstractWriter {
+ public:
+ explicit ABCInstanceWriter(const ABCWriterConstructorArgs &args);
+ virtual ~ABCInstanceWriter();
+
+ virtual void create_alembic_objects(const HierarchyContext *context) override;
+ virtual Alembic::Abc::OObject get_alembic_object() const override;
+
+ protected:
+ virtual bool is_supported(const HierarchyContext *context) const override;
+ virtual void do_write(HierarchyContext &context) override;
+};
+
+} // namespace alembic
+} // namespace io
+} // namespace blender
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index a27bb10f705..b8df98e8acb 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -271,7 +271,7 @@ void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_ob
std::set<Object *>::iterator it;
for (it = candidates.begin(); it != candidates.end(); ++it) {
Object *cob = *it;
- ListBase *conlist = ED_object_constraint_list_from_context(cob);
+ ListBase *conlist = ED_object_constraint_active_list(cob);
if (is_animated_by_constraint(cob, conlist, animated_objects)) {
animated_objects.insert(cob);
candidates.erase(cob);
diff --git a/source/blender/io/collada/TransformWriter.cpp b/source/blender/io/collada/TransformWriter.cpp
index 0311f22fe11..7c9d26e4fde 100644
--- a/source/blender/io/collada/TransformWriter.cpp
+++ b/source/blender/io/collada/TransformWriter.cpp
@@ -66,7 +66,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node &node,
bool limit_precision = export_settings.get_limit_precision();
/* Export the local Matrix (relative to the object parent,
- * be it an object, bone or vertex(-tices)). */
+ * be it an object, bone or vertices (one or more)). */
Matrix f_obmat;
BKE_object_matrix_local_get(ob, f_obmat);
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc
index 4910b7f11dd..0edfbc62d6b 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.cc
+++ b/source/blender/io/usd/intern/usd_writer_abstract.cc
@@ -21,6 +21,8 @@
#include <pxr/base/tf/stringUtils.h>
+#include "BLI_assert.h"
+
/* TfToken objects are not cheap to construct, so we do it once. */
namespace usdtokens {
// Materials
@@ -128,6 +130,31 @@ void USDAbstractWriter::write_visibility(const HierarchyContext &context,
usd_value_writer_.SetAttribute(attr_visibility, pxr::VtValue(visibility), timecode);
}
+/* Reference the original data instead of writing a copy. */
+bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim)
+{
+ BLI_assert(context.is_instance());
+
+ if (context.export_path == context.original_export_path) {
+ printf("USD ref error: export path is reference path: %s\n", context.export_path.c_str());
+ BLI_assert(!"USD reference error");
+ return false;
+ }
+
+ pxr::SdfPath ref_path(context.original_export_path);
+ if (!prim.GetReferences().AddInternalReference(ref_path)) {
+ /* See this URL for a description fo why referencing may fail"
+ * https://graphics.pixar.com/usd/docs/api/class_usd_references.html#Usd_Failing_References
+ */
+ printf("USD Export warning: unable to add reference from %s to %s, not instancing object\n",
+ context.export_path.c_str(),
+ context.original_export_path.c_str());
+ return false;
+ }
+
+ return true;
+}
+
} // namespace usd
} // namespace io
} // namespace blender
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 248bdd22a3b..6cf7c79c5fa 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -76,6 +76,10 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
void write_visibility(const HierarchyContext &context,
const pxr::UsdTimeCode timecode,
pxr::UsdGeomImageable &usd_geometry);
+
+ /* Turn `prim` into an instance referencing `context.original_export_path`.
+ * Return true when the instancing was successful, false otherwise. */
+ virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim);
};
} // namespace usd
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index 7d3ea911a65..2073d4cbe87 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -160,29 +160,18 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
get_geometry_data(mesh, usd_mesh_data);
if (usd_export_context_.export_params.use_instancing && context.is_instance()) {
- // This object data is instanced, just reference the original instead of writing a copy.
- if (context.export_path == context.original_export_path) {
- printf("USD ref error: export path is reference path: %s\n", context.export_path.c_str());
- BLI_assert(!"USD reference error");
- return;
- }
- pxr::SdfPath ref_path(context.original_export_path);
- if (!usd_mesh.GetPrim().GetReferences().AddInternalReference(ref_path)) {
- /* See this URL for a description fo why referencing may fail"
- * https://graphics.pixar.com/usd/docs/api/class_usd_references.html#Usd_Failing_References
- */
- printf("USD Export warning: unable to add reference from %s to %s, not instancing object\n",
- context.export_path.c_str(),
- context.original_export_path.c_str());
+ if (!mark_as_instance(context, usd_mesh.GetPrim())) {
return;
}
+
/* The material path will be of the form </_materials/{material name}>, which is outside the
- sub-tree pointed to by ref_path. As a result, the referenced data is not allowed to point out
- of its own sub-tree. It does work when we override the material with exactly the same path,
- though.*/
+ * sub-tree pointed to by ref_path. As a result, the referenced data is not allowed to point
+ * out of its own sub-tree. It does work when we override the material with exactly the same
+ * path, though.*/
if (usd_export_context_.export_params.export_materials) {
assign_materials(context, usd_mesh, usd_mesh_data.face_groups);
}
+
return;
}
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 2839d826df9..a9f1d5bcfc4 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -863,7 +863,7 @@ typedef struct BooleanModifierData {
struct Object *object;
char operation;
char solver;
- char _pad[1];
+ char flag;
char bm_flag;
float double_threshold;
} BooleanModifierData;
@@ -879,6 +879,10 @@ typedef enum {
eBooleanModifierSolver_Exact = 1,
} BooleanModifierSolver;
+enum {
+ eBooleanModifierFlag_Self = (1 << 0),
+};
+
/* bm_flag only used when G_DEBUG. */
enum {
eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 7d050b79aa0..9b1450467d1 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1534,8 +1534,9 @@ typedef struct UnitSettings {
char length_unit;
char mass_unit;
char time_unit;
+ char temperature_unit;
- char _pad[5];
+ char _pad[4];
} UnitSettings;
/* ------------------------------------------- */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index ad1635ba0c0..6fe6a5461e1 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -801,8 +801,10 @@ typedef enum eFileSel_Action {
} eFileSel_Action;
/* sfile->params->flag */
-/* Note: short flag, also used as 16 lower bits of flags in link/append code
- * (WM and BLO code area, see BLO_LibLinkFlags in BLO_readfile.h). */
+/**
+ * \note short flag, also used as 16 lower bits of flags in link/append code
+ * (WM and BLO code area, see #eBLOLibLinkFlags in BLO_readfile.h).
+ */
typedef enum eFileSel_Params_Flag {
FILE_PARAMS_FLAG_UNUSED_1 = (1 << 0), /* cleared */
FILE_RELPATH = (1 << 1),
@@ -813,8 +815,8 @@ typedef enum eFileSel_Params_Flag {
FILE_PARAMS_FLAG_UNUSED_6 = (1 << 6), /* cleared */
FILE_DIRSEL_ONLY = (1 << 7),
FILE_FILTER = (1 << 8),
- FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */
- FILE_GROUP_INSTANCE = (1 << 10),
+ FILE_OBDATA_INSTANCE = (1 << 9),
+ FILE_COLLECTION_INSTANCE = (1 << 10),
FILE_SORT_INVERT = (1 << 11),
FILE_HIDE_TOOL_PROPS = (1 << 12),
FILE_CHECK_EXISTING = (1 << 13),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index ec46d2680ca..589077ea67b 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -620,8 +620,9 @@ typedef struct UserDef_Experimental {
char use_new_hair_type;
char use_cycles_debug;
char use_sculpt_vertex_colors;
+ char use_tools_missing_icons;
/** `makesdna` does not allow empty structs. */
- char _pad[3];
+ char _pad[2];
} UserDef_Experimental;
#define USER_EXPERIMENTAL_TEST(userdef, member) \
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index ee7c045ebf9..1c488b2cac1 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -91,6 +91,7 @@ typedef enum PropertyUnit {
PROP_UNIT_ACCELERATION = (8 << 16), /* m/(s^2) */
PROP_UNIT_CAMERA = (9 << 16), /* mm */
PROP_UNIT_POWER = (10 << 16), /* W */
+ PROP_UNIT_TEMPERATURE = (11 << 16), /* C */
} PropertyUnit;
#define RNA_SUBTYPE_UNIT(subtype) ((subtype)&0x00FF0000)
@@ -156,6 +157,9 @@ typedef enum PropertySubType {
/** Light */
PROP_POWER = 42 | PROP_UNIT_POWER,
+
+ /* temperature */
+ PROP_TEMPERATURE = 43 | PROP_UNIT_TEMPERATURE,
} PropertySubType;
/* Make sure enums are updated with these */
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 2b1e5b3c702..a81bd4d0832 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3199,6 +3199,8 @@ static const char *rna_property_subtypename(PropertySubType type)
return "PROP_PASSWORD";
case PROP_POWER:
return "PROP_POWER";
+ case PROP_TEMPERATURE:
+ return "PROP_TEMPERATURE";
default: {
/* in case we don't have a type preset that includes the subtype */
if (RNA_SUBTYPE_UNIT(type)) {
@@ -3236,6 +3238,8 @@ static const char *rna_property_subtype_unit(PropertySubType type)
return "PROP_UNIT_CAMERA";
case PROP_UNIT_POWER:
return "PROP_UNIT_POWER";
+ case PROP_UNIT_TEMPERATURE:
+ return "PROP_UNIT_TEMPERATURE";
default:
return "PROP_UNIT_UNKNOWN";
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index d9e151e5f73..1bf14f86189 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -2863,6 +2863,11 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Solver", "Method for calculating booleans");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_self", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_Self);
+ RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
/* BMesh debugging options, only used when G_DEBUG is set */
/* BMesh intersection options */
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index e98fff13068..c7f625e2fa5 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -223,36 +223,39 @@ const EnumPropertyItem rna_enum_lightprobes_type_items[] = {
/* used for 2 enums */
#define OBTYPE_CU_CURVE \
{ \
- OB_CURVE, "CURVE", 0, "Curve", "" \
+ OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve", "" \
}
#define OBTYPE_CU_SURF \
{ \
- OB_SURF, "SURFACE", 0, "Surface", "" \
+ OB_SURF, "SURFACE", ICON_OUTLINER_OB_SURFACE, "Surface", "" \
}
#define OBTYPE_CU_FONT \
{ \
- OB_FONT, "FONT", 0, "Font", "" \
+ OB_FONT, "FONT", ICON_OUTLINER_OB_FONT, "Text", "" \
}
const EnumPropertyItem rna_enum_object_type_items[] = {
- {OB_MESH, "MESH", 0, "Mesh", ""},
+ {OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh", ""},
OBTYPE_CU_CURVE,
OBTYPE_CU_SURF,
- {OB_MBALL, "META", 0, "Meta", ""},
+ {OB_MBALL, "META", ICON_OUTLINER_OB_META, "Metaball", ""},
OBTYPE_CU_FONT,
- {OB_HAIR, "HAIR", 0, "Hair", ""},
- {OB_POINTCLOUD, "POINTCLOUD", 0, "PointCloud", ""},
- {OB_VOLUME, "VOLUME", 0, "Volume", ""},
+ {OB_HAIR, "HAIR", ICON_OUTLINER_OB_HAIR, "Hair", ""},
+ {OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Point Cloud", ""},
+ {OB_VOLUME, "VOLUME", ICON_OUTLINER_OB_VOLUME, "Volume", ""},
+ {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""},
{0, "", 0, NULL, NULL},
- {OB_ARMATURE, "ARMATURE", 0, "Armature", ""},
- {OB_LATTICE, "LATTICE", 0, "Lattice", ""},
- {OB_EMPTY, "EMPTY", 0, "Empty", ""},
- {OB_GPENCIL, "GPENCIL", 0, "GPencil", ""},
+ {OB_ARMATURE, "ARMATURE", ICON_OUTLINER_OB_ARMATURE, "Armature", ""},
+ {OB_LATTICE, "LATTICE", ICON_OUTLINER_OB_LATTICE, "Lattice", ""},
{0, "", 0, NULL, NULL},
- {OB_CAMERA, "CAMERA", 0, "Camera", ""},
- {OB_LAMP, "LIGHT", 0, "Light", ""},
- {OB_SPEAKER, "SPEAKER", 0, "Speaker", ""},
- {OB_LIGHTPROBE, "LIGHT_PROBE", 0, "Probe", ""},
+ {OB_EMPTY, "EMPTY", ICON_OUTLINER_OB_EMPTY, "Empty", ""},
+ {0, "", 0, NULL, NULL},
+ {OB_LAMP, "LIGHT", ICON_OUTLINER_OB_LIGHT, "Light", ""},
+ {OB_LIGHTPROBE, "LIGHT_PROBE", ICON_OUTLINER_OB_LIGHTPROBE, "Light Probe", ""},
+ {0, "", 0, NULL, NULL},
+ {OB_CAMERA, "CAMERA", ICON_OUTLINER_OB_CAMERA, "Camera", ""},
+ {0, "", 0, NULL, NULL},
+ {OB_SPEAKER, "SPEAKER", ICON_OUTLINER_OB_SPEAKER, "Speaker", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 5b77632be79..35563ad143e 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -100,7 +100,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
# include "BKE_context.h"
# include "BKE_report.h"
-# include "GPU_extensions.h"
+# include "GPU_capabilities.h"
# include "GPU_shader.h"
# include "IMB_colormanagement.h"
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 9f5440be9f8..c7076d6c631 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -117,6 +117,7 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
{PROP_UNIT_MASS, "MASS", 0, "Mass", ""},
{PROP_UNIT_CAMERA, "CAMERA", 0, "Camera", ""},
{PROP_UNIT_POWER, "POWER", 0, "Power", ""},
+ {PROP_UNIT_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 65edaf0bcca..bf97e4fcc0f 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2514,7 +2514,7 @@ static const EnumPropertyItem *rna_UnitSettings_itemf_wrapper(const int system,
{
const void *usys;
int len;
- bUnit_GetSystem(system, type, &usys, &len);
+ BKE_unit_system_get(system, type, &usys, &len);
EnumPropertyItem *items = NULL;
int totitem = 0;
@@ -2526,10 +2526,10 @@ static const EnumPropertyItem *rna_UnitSettings_itemf_wrapper(const int system,
RNA_enum_item_add(&items, &totitem, &adaptive);
for (int i = 0; i < len; i++) {
- if (!bUnit_IsSuppressed(usys, i)) {
+ if (!BKE_unit_is_suppressed(usys, i)) {
EnumPropertyItem tmp = {0};
- tmp.identifier = bUnit_GetIdentifier(usys, i);
- tmp.name = bUnit_GetNameDisplay(usys, i);
+ tmp.identifier = BKE_unit_identifier_get(usys, i);
+ tmp.name = BKE_unit_display_name_get(usys, i);
tmp.value = i;
RNA_enum_item_add(&items, &totitem, &tmp);
}
@@ -2568,6 +2568,15 @@ const EnumPropertyItem *rna_UnitSettings_time_unit_itemf(bContext *UNUSED(C),
return rna_UnitSettings_itemf_wrapper(units->system, B_UNIT_TIME, r_free);
}
+const EnumPropertyItem *rna_UnitSettings_temperature_unit_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ UnitSettings *units = ptr->data;
+ return rna_UnitSettings_itemf_wrapper(units->system, B_UNIT_TEMPERATURE, r_free);
+}
+
static void rna_UnitSettings_system_update(Main *UNUSED(bmain),
Scene *scene,
PointerRNA *UNUSED(ptr))
@@ -2578,8 +2587,8 @@ static void rna_UnitSettings_system_update(Main *UNUSED(bmain),
unit->mass_unit = USER_UNIT_ADAPTIVE;
}
else {
- unit->length_unit = bUnit_GetBaseUnitOfType(unit->system, B_UNIT_LENGTH);
- unit->mass_unit = bUnit_GetBaseUnitOfType(unit->system, B_UNIT_MASS);
+ unit->length_unit = BKE_unit_base_of_type_get(unit->system, B_UNIT_LENGTH);
+ unit->mass_unit = BKE_unit_base_of_type_get(unit->system, B_UNIT_MASS);
}
}
@@ -3480,7 +3489,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_edge_path_live_unwrap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1);
- RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam recalculates UV unwrap");
+ RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edge seams recalculates UV unwrap");
prop = RNA_def_property(srna, "normal_vector", PROP_FLOAT, PROP_XYZ);
RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply");
@@ -3906,6 +3915,13 @@ static void rna_def_unit_settings(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_UnitSettings_time_unit_itemf");
RNA_def_property_ui_text(prop, "Time Unit", "Unit that will be used to display time values");
RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "temperature_unit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_UnitSettings_temperature_unit_itemf");
+ RNA_def_property_ui_text(
+ prop, "Temperature Unit", "Unit that will be used to display temperature values");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
}
static void rna_def_view_layer_eevee(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 6682cd743eb..10e3f9c86ee 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -188,7 +188,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "DEG_depsgraph.h"
-# include "GPU_extensions.h"
+# include "GPU_capabilities.h"
# include "GPU_select.h"
# include "GPU_texture.h"
@@ -6117,6 +6117,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_sculpt_vertex_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_vertex_colors", 1);
RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "Use the new Vertex Painting system");
+
+ prop = RNA_def_property(srna, "use_tools_missing_icons", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_tools_missing_icons", 1);
+ RNA_def_property_ui_text(prop, "Tools with Missing Icons", "Show tools with missing icons");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 87489c90de3..bef7d5d8e4f 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -77,6 +77,7 @@ static void initData(ModifierData *md)
bmd->double_threshold = 1e-6f;
bmd->operation = eBooleanModifierOp_Difference;
bmd->solver = eBooleanModifierSolver_Exact;
+ bmd->flag = 0;
}
static bool isDisabled(const struct Scene *UNUSED(scene),
@@ -319,15 +320,18 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#ifdef WITH_GMP
const bool use_exact = bmd->solver == eBooleanModifierSolver_Exact;
+ const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
#else
if (bmd->solver == eBooleanModifierSolver_Exact) {
BKE_modifier_set_error(md, "Compiled without GMP, using fast solver");
}
const bool use_exact = false;
+ const bool use_self = false;
#endif
if (use_exact) {
- BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, false, bmd->operation);
+ BM_mesh_boolean(
+ bm, looptris, tottri, bm_face_isect_pair, NULL, use_self, bmd->operation);
}
else {
BM_mesh_intersect(bm,
@@ -393,7 +397,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- if (!use_exact) {
+ if (use_exact) {
+ uiItemR(layout, ptr, "use_self", 0, NULL, ICON_NONE);
+ }
+ else {
uiItemR(layout, ptr, "double_threshold", 0, NULL, ICON_NONE);
}
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 68c330452b3..72a868cc6a7 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -257,6 +257,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_collapse_triangulate", 0, NULL, ICON_NONE);
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
+ sub = uiLayoutRow(layout, true);
+ bool has_vertex_group = RNA_string_length(ptr, "vertex_group") != 0;
+ uiLayoutSetActive(sub, has_vertex_group);
+ uiItemR(sub, ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
}
else if (decimate_type == MOD_DECIM_MODE_UNSUBDIV) {
uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 7bdc1da33c2..9c7ab50cb61 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -205,6 +205,13 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd,
}
BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh);
+
+ /* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share
+ * this pointer. Not sure if it's needed, but might have a second look
+ * on the ownership model here. */
+ MultiresRuntimeData *runtime_data = mmd->modifier.runtime;
+ runtime_data->subdiv = NULL;
+
return result;
}
@@ -261,10 +268,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
sculpt_session->mpoly = NULL;
sculpt_session->mloop = NULL;
}
- /* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share
- * this pointer. Not sure if it's needed, but might have a second look
- * on the ownership model here. */
- runtime_data->subdiv = NULL;
// BKE_subdiv_stats_print(&subdiv->stats);
}
else {
@@ -293,7 +296,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
static void deformMatrices(ModifierData *md,
- const ModifierEvalContext *UNUSED(ctx),
+ const ModifierEvalContext *ctx,
Mesh *mesh,
float (*vertex_cos)[3],
float (*deform_matrices)[3][3],
@@ -309,11 +312,19 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
MultiresModifierData *mmd = (MultiresModifierData *)md;
+
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
if (subdiv_settings.level == 0) {
return;
}
+
+ SubdivToCCGSettings ccg_settings;
+ multires_ccg_settings_init(&ccg_settings, mmd, ctx, mesh);
+ if (ccg_settings.resolution < 3) {
+ return;
+ }
+
BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index bdad4d03ae7..a3750d348f5 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -327,7 +327,10 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* here appending/linking starts */
- mainl = BLO_library_link_begin(bmain, &(self->blo_handle), self->relpath);
+ struct LibraryLink_Params liblink_params;
+ BLO_library_link_params_init(&liblink_params, bmain, self->flag);
+
+ mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
{
int idcode_step = 0, idcode;
@@ -350,7 +353,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
if (item_idname) {
ID *id = BLO_library_link_named_part(
- mainl, &(self->blo_handle), idcode, item_idname);
+ mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
if (id) {
#ifdef USE_RNA_DATABLOCKS
/* swap name for pointer to the id */
@@ -394,7 +397,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
}
Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL, NULL, NULL);
+ BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params);
BLO_blendhandle_close(self->blo_handle);
self->blo_handle = NULL;
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index a78ed601d57..bc708bd4a89 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -172,6 +172,7 @@ static const EnumPropertyItem property_subtype_array_items[] = {
{PROP_LAYER, "LAYER", 0, "Layer", ""},
{PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""},
{PROP_POWER, "POWER", 0, "Power", ""},
+ {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
{PROP_NONE, "NONE", 0, "None", ""},
{0, NULL, 0, NULL, NULL},
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index cc981c7c2e1..0980d9df762 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -219,10 +219,10 @@ static void value_id_set(void *id)
}
static void id_release_weakref_list(struct ID *id, GHash *weakinfo_hash);
-static PyObject *id_free_weakref_cb(PyObject *weakinfo_capsule, PyObject *weakref)
+static PyObject *id_free_weakref_cb(PyObject *weakinfo_pair, PyObject *weakref)
{
/* Important to search backwards. */
- GHash *weakinfo_hash = PyCapsule_GetPointer(weakinfo_capsule, NULL);
+ GHash *weakinfo_hash = PyCapsule_GetPointer(weakinfo_pair, NULL);
if (BLI_ghash_len(weakinfo_hash) > 1) {
BLI_ghash_remove(weakinfo_hash, weakref, NULL, NULL);
diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c
index 575824e8a86..542d014f8b2 100644
--- a/source/blender/python/intern/bpy_rna_gizmo.c
+++ b/source/blender/python/intern/bpy_rna_gizmo.c
@@ -507,7 +507,7 @@ fail:
/** \} */
-int BPY_rna_gizmo_module(PyObject *mod_par)
+bool BPY_rna_gizmo_module(PyObject *mod_par)
{
static PyMethodDef method_def_array[] = {
/* Gizmo Target Property Define API */
@@ -541,5 +541,5 @@ int BPY_rna_gizmo_module(PyObject *mod_par)
PyModule_AddObject(mod_par, name_prefix, func_inst);
}
- return 0;
+ return false;
}
diff --git a/source/blender/python/intern/bpy_rna_gizmo.h b/source/blender/python/intern/bpy_rna_gizmo.h
index 307b694338c..e4ac43bfe6c 100644
--- a/source/blender/python/intern/bpy_rna_gizmo.h
+++ b/source/blender/python/intern/bpy_rna_gizmo.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-int BPY_rna_gizmo_module(PyObject *);
+bool BPY_rna_gizmo_module(PyObject *);
#ifdef __cplusplus
}
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 4433f5d0f88..a58e2bcb975 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -134,7 +134,7 @@ static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r
return false;
}
- if (!bUnit_IsValid(*r_usys, *r_ucat)) {
+ if (!BKE_unit_is_valid(*r_usys, *r_ucat)) {
PyErr_Format(PyExc_ValueError,
"%.200s / %.200s unit system/category combination is not valid.",
usys_str,
@@ -197,7 +197,7 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
str = PyMem_MALLOC(sizeof(*str) * (size_t)str_len);
BLI_strncpy(str, inpt, (size_t)str_len);
- bUnit_ReplaceString(str, (int)str_len, uref, scale, usys, ucat);
+ BKE_unit_replace_string(str, (int)str_len, uref, scale, usys, ucat);
if (!PyC_RunString_AsNumber(NULL, str, "<bpy_units_api>", &result)) {
if (PyErr_Occurred()) {
@@ -291,10 +291,11 @@ static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyOb
char buf1[64], buf2[64], *str;
PyObject *result;
- bUnit_AsString(buf1, sizeof(buf1), value, precision, usys, ucat, (bool)split_unit, false);
+ BKE_unit_value_as_string_adaptive(
+ buf1, sizeof(buf1), value, precision, usys, ucat, (bool)split_unit, false);
if (compatible_unit) {
- bUnit_ToUnitAltName(buf2, sizeof(buf2), buf1, usys, ucat);
+ BKE_unit_name_to_alt(buf2, sizeof(buf2), buf1, usys, ucat);
str = buf2;
}
else {
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 8c61fd5b971..2d581a4765e 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -1113,7 +1113,7 @@ void *RE_gl_context_get(Render *re)
void *RE_gpu_context_get(Render *re)
{
if (re->gpu_context == NULL) {
- re->gpu_context = GPU_context_create(0);
+ re->gpu_context = GPU_context_create(NULL);
}
return re->gpu_context;
}
diff --git a/source/blender/shader_fx/intern/FX_shader_light.c b/source/blender/shader_fx/intern/FX_shader_light.c
deleted file mode 100644
index 2fd93bff8aa..00000000000
--- a/source/blender/shader_fx/intern/FX_shader_light.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2018, Blender Foundation
- * This is a new part of Blender
- */
-
-/** \file
- * \ingroup shader_fx
- */
-
-#include <stdio.h>
-
-#include "DNA_gpencil_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-#include "BKE_lib_query.h"
-#include "BKE_modifier.h"
-#include "BKE_screen.h"
-#include "BKE_shader_fx.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "RNA_access.h"
-
-#include "FX_shader_types.h"
-#include "FX_ui_common.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
-static void initData(ShaderFxData *fx)
-{
- LightShaderFxData *gpfx = (LightShaderFxData *)fx;
- gpfx->energy = 10.0f;
- gpfx->ambient = 5.0f;
- gpfx->object = NULL;
-}
-
-static void copyData(const ShaderFxData *md, ShaderFxData *target)
-{
- BKE_shaderfx_copydata_generic(md, target);
-}
-
-static void updateDepsgraph(ShaderFxData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- LightShaderFxData *fxd = (LightShaderFxData *)md;
- if (fxd->object != NULL) {
- DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx");
- }
- DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx");
-}
-
-static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams))
-{
- LightShaderFxData *fxd = (LightShaderFxData *)fx;
-
- return !fxd->object;
-}
-
-static void foreachObjectLink(ShaderFxData *fx,
- Object *ob,
- ShaderFxObjectWalkFunc walk,
- void *userData)
-{
- LightShaderFxData *fxd = (LightShaderFxData *)fx;
-
- walk(userData, ob, &fxd->object, IDWALK_CB_NOP);
-}
-
-ShaderFxTypeInfo shaderfx_Type_Light = {
- /* name */ "Light",
- /* structName */ "LightShaderFxData",
- /* structSize */ sizeof(LightShaderFxData),
- /* type */ eShaderFxType_GpencilType,
- /* flags */ 0,
-
- /* copyData */ copyData,
-
- /* initData */ initData,
- /* freeData */ NULL,
- /* isDisabled */ isDisabled,
- /* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ NULL,
- /* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
- /* panelRegister */ NULL,
-};
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 6ccc5d79962..6ed9dcd4cdc 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -135,7 +135,10 @@ static short wm_link_append_flag(wmOperator *op)
flag |= FILE_LINK;
}
if (RNA_boolean_get(op->ptr, "instance_collections")) {
- flag |= FILE_GROUP_INSTANCE;
+ flag |= FILE_COLLECTION_INSTANCE;
+ }
+ if (RNA_boolean_get(op->ptr, "instance_object_data")) {
+ flag |= FILE_OBDATA_INSTANCE;
}
return flag;
@@ -156,8 +159,9 @@ typedef struct WMLinkAppendData {
LinkNodePair items;
int num_libraries;
int num_items;
- /** Combines #eFileSel_Params_Flag from DNA_space_types.h and
- * BLO_LibLinkFlags from BLO_readfile.h */
+ /**
+ * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h
+ */
int flag;
/* Internal 'private' data */
@@ -250,7 +254,11 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
}
/* here appending/linking starts */
- mainl = BLO_library_link_begin(bmain, &bh, libname);
+ struct LibraryLink_Params liblink_params;
+ BLO_library_link_params_init_with_context(
+ &liblink_params, bmain, flag, scene, view_layer, v3d);
+
+ mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
lib = mainl->curlib;
BLI_assert(lib);
UNUSED_VARS_NDEBUG(lib);
@@ -276,7 +284,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
continue;
}
- new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag);
+ new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params);
if (new_id) {
/* If the link is successful, clear item's libs 'todo' flags.
@@ -286,7 +294,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
}
}
- BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer, v3d);
+ BLO_library_link_end(mainl, &bh, &liblink_params);
BLO_blendhandle_close(bh);
}
}
@@ -389,13 +397,13 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (scene && scene->id.lib) {
BKE_reportf(op->reports,
RPT_WARNING,
- "Scene '%s' is linked, instantiation of objects & groups is disabled",
+ "Scene '%s' is linked, instantiation of objects is disabled",
scene->id.name + 2);
- flag &= ~FILE_GROUP_INSTANCE;
+ flag &= ~(FILE_COLLECTION_INSTANCE | FILE_OBDATA_INSTANCE);
scene = NULL;
}
- /* We need to add nothing from BLO_LibLinkFlags to flag here. */
+ /* We need to add nothing from #eBLOLibLinkFlags to flag here. */
/* from here down, no error returns */
@@ -562,6 +570,14 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
"Instance Collections",
"Create instances for collections, rather than adding them directly to the scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "instance_object_data",
+ true,
+ "Instance Object Data",
+ "Create instances for object data which are not referenced by any objects");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
void WM_OT_link(wmOperatorType *ot)
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 98beae69672..ffe2ffac3a2 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3903,6 +3903,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "MASK_OT_select_box");
WM_modalkeymap_assign(keymap, "PAINT_OT_mask_box_gesture");
WM_modalkeymap_assign(keymap, "SCULPT_OT_face_set_box_gesture");
+ WM_modalkeymap_assign(keymap, "SCULPT_OT_trim_box_gesture");
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 86d3f7f35dc..e3c763930c0 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1292,7 +1292,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* initialize OpenGL immediate mode */
g_WS.gpu_context = GPU_context_create(g_WS.ghost_window);
GPU_init();
- immActivate();
/* initialize the font */
BLF_init();
@@ -1579,8 +1578,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GPU_shader_free_builtin_shaders();
- immDeactivate();
-
if (g_WS.gpu_context) {
GPU_context_active_set(g_WS.gpu_context);
GPU_context_discard(g_WS.gpu_context);
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 9667ed5b631..ab6da2cc947 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -40,7 +40,7 @@
#include "ED_screen.h"
-#include "GPU_extensions.h"
+#include "GPU_capabilities.h"
#include "GPU_immediate.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c
index e8cb5d9cd7d..4139574460b 100644
--- a/source/blender/windowmanager/intern/wm_surface.c
+++ b/source/blender/windowmanager/intern/wm_surface.c
@@ -56,8 +56,6 @@ void wm_surface_clear_drawable(void)
WM_opengl_context_release(g_drawable->ghost_ctx);
GPU_context_active_set(NULL);
- immDeactivate();
-
if (g_drawable->deactivate) {
g_drawable->deactivate();
}
@@ -79,7 +77,6 @@ void wm_surface_set_drawable(wmSurface *surface, bool activate)
}
GPU_context_active_set(surface->gpu_ctx);
- immActivate();
}
void wm_surface_make_drawable(wmSurface *surface)
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 0e19f79e659..795205b8200 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1099,13 +1099,11 @@ static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool acti
GHOST_ActivateWindowDrawingContext(win->ghostwin);
}
GPU_context_active_set(win->gpuctx);
- immActivate();
}
void wm_window_clear_drawable(wmWindowManager *wm)
{
if (wm->windrawable) {
- immDeactivate();
wm->windrawable = NULL;
}
}