diff options
author | Falk David <falkdavid@gmx.de> | 2020-09-12 12:43:55 +0300 |
---|---|---|
committer | Falk David <falkdavid@gmx.de> | 2020-09-12 12:43:55 +0300 |
commit | 8156e948042a464ca40ca78c946874340a8421f4 (patch) | |
tree | 903da71b516220f1113b68ce1b11ce4fff437aea | |
parent | 34063250aef35c2e4e03664da9ade24ca151f683 (diff) | |
parent | 91066cd0c3b9737feb85ea72abc7e021124639aa (diff) |
Merge branch 'greasepencil-edit-curve' into soc-2020-greasepencil-curve
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, ®ion->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 = ®ion->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 = ®ion->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(®ion->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(®ion->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; } } |