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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2021-03-18 03:28:56 +0300
committerHans Goudey <h.goudey@me.com>2021-03-18 03:32:17 +0300
commit7bbd24e1d5c52a08205f0cc5921c305397dcac49 (patch)
tree2f93e627e8924de4199da0dd0c636ebd1b77152f
parent9683976b0229e01aca3ae0f9293d9f837efecb1c (diff)
parentde6d6e171e950ab59e8499f310a91ee7fc18c9f8 (diff)
Merge branch 'master' into geometry-nodes-read-only-instances
-rw-r--r--.clang-format1
-rw-r--r--CMakeLists.txt37
-rw-r--r--GNUmakefile2
-rw-r--r--build_files/build_environment/CMakeLists.txt1
-rw-r--r--build_files/build_environment/cmake/alembic.cmake4
-rw-r--r--build_files/build_environment/cmake/blosc.cmake4
-rw-r--r--build_files/build_environment/cmake/boost.cmake4
-rw-r--r--build_files/build_environment/cmake/bzip2.cmake4
-rw-r--r--build_files/build_environment/cmake/check_software.cmake5
-rw-r--r--build_files/build_environment/cmake/clew.cmake4
-rw-r--r--build_files/build_environment/cmake/cuew.cmake4
-rw-r--r--build_files/build_environment/cmake/download.cmake93
-rw-r--r--build_files/build_environment/cmake/embree.cmake4
-rw-r--r--build_files/build_environment/cmake/expat.cmake4
-rw-r--r--build_files/build_environment/cmake/ffi.cmake4
-rw-r--r--build_files/build_environment/cmake/ffmpeg.cmake4
-rw-r--r--build_files/build_environment/cmake/fftw.cmake4
-rw-r--r--build_files/build_environment/cmake/flac.cmake4
-rw-r--r--build_files/build_environment/cmake/flexbison.cmake4
-rw-r--r--build_files/build_environment/cmake/freeglut.cmake4
-rw-r--r--build_files/build_environment/cmake/freetype.cmake4
-rw-r--r--build_files/build_environment/cmake/glew.cmake4
-rw-r--r--build_files/build_environment/cmake/glfw.cmake4
-rw-r--r--build_files/build_environment/cmake/gmp.cmake8
-rw-r--r--build_files/build_environment/cmake/haru.cmake4
-rw-r--r--build_files/build_environment/cmake/iconv.cmake4
-rw-r--r--build_files/build_environment/cmake/ispc.cmake4
-rw-r--r--build_files/build_environment/cmake/jemalloc.cmake4
-rw-r--r--build_files/build_environment/cmake/jpeg.cmake8
-rw-r--r--build_files/build_environment/cmake/lame.cmake4
-rw-r--r--build_files/build_environment/cmake/libglu.cmake4
-rw-r--r--build_files/build_environment/cmake/llvm.cmake4
-rw-r--r--build_files/build_environment/cmake/lzma.cmake4
-rw-r--r--build_files/build_environment/cmake/mesa.cmake4
-rw-r--r--build_files/build_environment/cmake/nanovdb.cmake4
-rw-r--r--build_files/build_environment/cmake/nasm.cmake4
-rw-r--r--build_files/build_environment/cmake/numpy.cmake4
-rw-r--r--build_files/build_environment/cmake/ogg.cmake4
-rw-r--r--build_files/build_environment/cmake/openal.cmake4
-rw-r--r--build_files/build_environment/cmake/opencollada.cmake4
-rw-r--r--build_files/build_environment/cmake/opencolorio.cmake4
-rw-r--r--build_files/build_environment/cmake/openexr.cmake4
-rw-r--r--build_files/build_environment/cmake/openimagedenoise.cmake4
-rw-r--r--build_files/build_environment/cmake/openimageio.cmake4
-rw-r--r--build_files/build_environment/cmake/openjpeg.cmake8
-rw-r--r--build_files/build_environment/cmake/openmp.cmake4
-rw-r--r--build_files/build_environment/cmake/opensubdiv.cmake4
-rw-r--r--build_files/build_environment/cmake/openvdb.cmake4
-rw-r--r--build_files/build_environment/cmake/options.cmake14
-rw-r--r--build_files/build_environment/cmake/opus.cmake4
-rw-r--r--build_files/build_environment/cmake/osl.cmake4
-rw-r--r--build_files/build_environment/cmake/png.cmake4
-rw-r--r--build_files/build_environment/cmake/potrace.cmake4
-rw-r--r--build_files/build_environment/cmake/pthreads.cmake4
-rw-r--r--build_files/build_environment/cmake/pugixml.cmake4
-rw-r--r--build_files/build_environment/cmake/python.cmake8
-rw-r--r--build_files/build_environment/cmake/sdl.cmake4
-rw-r--r--build_files/build_environment/cmake/sndfile.cmake4
-rw-r--r--build_files/build_environment/cmake/spnav.cmake4
-rw-r--r--build_files/build_environment/cmake/sqlite.cmake4
-rw-r--r--build_files/build_environment/cmake/ssl.cmake4
-rw-r--r--build_files/build_environment/cmake/tbb.cmake4
-rw-r--r--build_files/build_environment/cmake/theora.cmake4
-rw-r--r--build_files/build_environment/cmake/tiff.cmake4
-rw-r--r--build_files/build_environment/cmake/usd.cmake4
-rw-r--r--build_files/build_environment/cmake/versions.cmake162
-rw-r--r--build_files/build_environment/cmake/vorbis.cmake4
-rw-r--r--build_files/build_environment/cmake/vpx.cmake4
-rw-r--r--build_files/build_environment/cmake/webp.cmake4
-rw-r--r--build_files/build_environment/cmake/x264.cmake4
-rw-r--r--build_files/build_environment/cmake/xml2.cmake4
-rw-r--r--build_files/build_environment/cmake/xr_openxr.cmake4
-rw-r--r--build_files/build_environment/cmake/xvidcore.cmake4
-rw-r--r--build_files/build_environment/cmake/yamlcpp.cmake4
-rw-r--r--build_files/build_environment/cmake/zlib.cmake5
-rw-r--r--build_files/build_environment/cmake/zlib_mingw.cmake4
-rwxr-xr-xbuild_files/build_environment/install_deps.sh33
-rw-r--r--build_files/build_environment/windows/build_deps.cmd4
-rw-r--r--build_files/buildbot/config/blender_linux.cmake1
-rw-r--r--build_files/cmake/Modules/FindPulse.cmake60
-rw-r--r--build_files/cmake/config/blender_full.cmake7
-rw-r--r--build_files/cmake/config/blender_headless.cmake3
-rw-r--r--build_files/cmake/config/blender_lite.cmake3
-rw-r--r--build_files/cmake/config/blender_release.cmake7
-rw-r--r--build_files/cmake/config/bpy_module.cmake3
-rw-r--r--build_files/cmake/macros.cmake3
-rw-r--r--build_files/cmake/platform/platform_apple_xcode.cmake2
-rw-r--r--build_files/cmake/platform/platform_unix.cmake8
-rwxr-xr-xbuild_files/utils/make_source_archive.py198
-rwxr-xr-xbuild_files/utils/make_source_archive.sh82
-rw-r--r--doc/doxygen/doxygen.intern.h9
-rw-r--r--extern/audaspace/CMakeLists.txt151
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.cpp2
-rw-r--r--extern/audaspace/blender_config.cmake5
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp235
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioDevice.h100
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp127
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h64
-rw-r--r--extern/audaspace/plugins/jack/JackLibrary.h3
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp282
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h105
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.cpp59
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.h46
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h41
-rw-r--r--extern/audaspace/plugins/wasapi/WASAPIDevice.cpp401
-rw-r--r--extern/audaspace/plugins/wasapi/WASAPIDevice.h99
-rw-r--r--extern/audaspace/src/devices/NULLDevice.cpp2
-rw-r--r--extern/audaspace/src/plugin/PluginManagerUnix.cpp.in5
-rw-r--r--extern/audaspace/src/plugin/PluginManagerWindows.cpp.in4
-rw-r--r--extern/mantaflow/CMakeLists.txt4
-rw-r--r--intern/clog/clog.c52
-rw-r--r--intern/cycles/blender/blender_shader.cpp3
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp4
-rw-r--r--intern/cycles/device/cuda/device_cuda_impl.cpp12
-rw-r--r--intern/cycles/device/device_cpu.cpp5
-rw-r--r--intern/cycles/device/device_denoising.h3
-rw-r--r--intern/cycles/device/device_memory.h4
-rw-r--r--intern/cycles/device/device_optix.cpp23
-rw-r--r--intern/cycles/device/device_task.cpp11
-rw-r--r--intern/cycles/graph/node_type.cpp2
-rw-r--r--intern/cycles/graph/node_type.h27
-rw-r--r--intern/cycles/graph/node_xml.cpp4
-rw-r--r--intern/cycles/kernel/kernel_montecarlo.h117
-rw-r--r--intern/cycles/kernel/kernel_volume.h75
-rw-r--r--intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h16
-rw-r--r--intern/cycles/kernel/shaders/node_attribute.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_light_path.osl10
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_tangent.osl2
-rw-r--r--intern/cycles/kernel/shaders/stdcycles.h69
-rw-r--r--intern/cycles/render/alembic.cpp379
-rw-r--r--intern/cycles/render/alembic.h122
-rw-r--r--intern/cycles/render/background.cpp4
-rw-r--r--intern/cycles/render/camera.cpp2
-rw-r--r--intern/cycles/render/film.cpp4
-rw-r--r--intern/cycles/render/geometry.cpp4
-rw-r--r--intern/cycles/render/hair.cpp4
-rw-r--r--intern/cycles/render/integrator.cpp2
-rw-r--r--intern/cycles/render/light.cpp10
-rw-r--r--intern/cycles/render/mesh.cpp4
-rw-r--r--intern/cycles/render/nodes.cpp180
-rw-r--r--intern/cycles/render/object.cpp6
-rw-r--r--intern/cycles/render/particles.cpp2
-rw-r--r--intern/cycles/render/scene.cpp36
-rw-r--r--intern/cycles/render/shader.cpp38
-rw-r--r--intern/cycles/render/volume.cpp4
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm2
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm490
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h6
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm5
-rw-r--r--intern/ghost/intern/GHOST_WindowViewCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp11
-rw-r--r--intern/guardedalloc/CMakeLists.txt1
-rw-r--r--intern/libmv/.clang-format36
-rw-r--r--intern/libmv/intern/autotrack.cc35
-rw-r--r--intern/libmv/intern/autotrack.h10
-rw-r--r--intern/libmv/intern/camera_intrinsics.cc436
-rw-r--r--intern/libmv/intern/camera_intrinsics.h12
-rw-r--r--intern/libmv/intern/detector.cc16
-rw-r--r--intern/libmv/intern/detector.h2
-rw-r--r--intern/libmv/intern/frame_accessor.cc101
-rw-r--r--intern/libmv/intern/frame_accessor.h19
-rw-r--r--intern/libmv/intern/homography.cc6
-rw-r--r--intern/libmv/intern/image.cc64
-rw-r--r--intern/libmv/intern/image.h30
-rw-r--r--intern/libmv/intern/reconstruction.cc229
-rw-r--r--intern/libmv/intern/reconstruction.h46
-rw-r--r--intern/libmv/intern/stub.cc214
-rw-r--r--intern/libmv/intern/track_region.cc80
-rw-r--r--intern/libmv/intern/track_region.h14
-rw-r--r--intern/libmv/intern/tracks.cc6
-rw-r--r--intern/libmv/intern/tracksN.cc39
-rw-r--r--intern/libmv/intern/tracksN.h10
-rw-r--r--intern/libmv/intern/utildefines.h36
-rw-r--r--intern/libmv/libmv/autotrack/autotrack.cc83
-rw-r--r--intern/libmv/libmv/autotrack/autotrack.h58
-rw-r--r--intern/libmv/libmv/autotrack/frame_accessor.h9
-rw-r--r--intern/libmv/libmv/autotrack/marker.h39
-rw-r--r--intern/libmv/libmv/autotrack/model.h9
-rw-r--r--intern/libmv/libmv/autotrack/predict_tracks.cc78
-rw-r--r--intern/libmv/libmv/autotrack/predict_tracks.h20
-rw-r--r--intern/libmv/libmv/autotrack/predict_tracks_test.cc56
-rw-r--r--intern/libmv/libmv/autotrack/quad.h6
-rw-r--r--intern/libmv/libmv/autotrack/reconstruction.h12
-rw-r--r--intern/libmv/libmv/autotrack/region.h2
-rw-r--r--intern/libmv/libmv/autotrack/tracks.cc43
-rw-r--r--intern/libmv/libmv/autotrack/tracks.h12
-rw-r--r--intern/libmv/libmv/autotrack/tracks_test.cc2
-rw-r--r--intern/libmv/libmv/base/aligned_malloc.cc6
-rw-r--r--intern/libmv/libmv/base/aligned_malloc.h4
-rw-r--r--intern/libmv/libmv/base/id_generator.h1
-rw-r--r--intern/libmv/libmv/base/map.h2
-rw-r--r--intern/libmv/libmv/base/scoped_ptr.h38
-rw-r--r--intern/libmv/libmv/base/scoped_ptr_test.cc8
-rw-r--r--intern/libmv/libmv/base/vector_test.cc8
-rw-r--r--intern/libmv/libmv/base/vector_utils.h5
-rw-r--r--intern/libmv/libmv/image/array_nd.cc27
-rw-r--r--intern/libmv/libmv/image/array_nd.h188
-rw-r--r--intern/libmv/libmv/image/array_nd_test.cc10
-rw-r--r--intern/libmv/libmv/image/convolve.cc170
-rw-r--r--intern/libmv/libmv/image/convolve.h62
-rw-r--r--intern/libmv/libmv/image/convolve_test.cc12
-rw-r--r--intern/libmv/libmv/image/correlation.h11
-rw-r--r--intern/libmv/libmv/image/image.h93
-rw-r--r--intern/libmv/libmv/image/image_converter.h21
-rw-r--r--intern/libmv/libmv/image/image_drawing.h112
-rw-r--r--intern/libmv/libmv/image/image_test.cc6
-rw-r--r--intern/libmv/libmv/image/sample.h40
-rw-r--r--intern/libmv/libmv/image/sample_test.cc14
-rw-r--r--intern/libmv/libmv/image/tuple.h32
-rw-r--r--intern/libmv/libmv/multiview/conditioning.cc28
-rw-r--r--intern/libmv/libmv/multiview/conditioning.h24
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection.cc198
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection.h47
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection_test.cc74
-rw-r--r--intern/libmv/libmv/multiview/fundamental.cc227
-rw-r--r--intern/libmv/libmv/multiview/fundamental.h115
-rw-r--r--intern/libmv/libmv/multiview/fundamental_test.cc8
-rw-r--r--intern/libmv/libmv/multiview/homography.cc249
-rw-r--r--intern/libmv/libmv/multiview/homography.h34
-rw-r--r--intern/libmv/libmv/multiview/homography_error.h120
-rw-r--r--intern/libmv/libmv/multiview/homography_parameterization.h36
-rw-r--r--intern/libmv/libmv/multiview/homography_test.cc40
-rw-r--r--intern/libmv/libmv/multiview/nviewtriangulation.h32
-rw-r--r--intern/libmv/libmv/multiview/nviewtriangulation_test.cc4
-rw-r--r--intern/libmv/libmv/multiview/panography.cc47
-rw-r--r--intern/libmv/libmv/multiview/panography.h12
-rw-r--r--intern/libmv/libmv/multiview/panography_kernel.cc4
-rw-r--r--intern/libmv/libmv/multiview/panography_kernel.h18
-rw-r--r--intern/libmv/libmv/multiview/panography_test.cc26
-rw-r--r--intern/libmv/libmv/multiview/projection.cc58
-rw-r--r--intern/libmv/libmv/multiview/projection.h124
-rw-r--r--intern/libmv/libmv/multiview/projection_test.cc18
-rw-r--r--intern/libmv/libmv/multiview/resection.h18
-rw-r--r--intern/libmv/libmv/multiview/resection_test.cc8
-rw-r--r--intern/libmv/libmv/multiview/test_data_sets.cc33
-rw-r--r--intern/libmv/libmv/multiview/test_data_sets.h42
-rw-r--r--intern/libmv/libmv/multiview/triangulation.cc18
-rw-r--r--intern/libmv/libmv/multiview/triangulation.h16
-rw-r--r--intern/libmv/libmv/multiview/triangulation_test.cc2
-rw-r--r--intern/libmv/libmv/multiview/two_view_kernel.h31
-rw-r--r--intern/libmv/libmv/numeric/dogleg.h119
-rw-r--r--intern/libmv/libmv/numeric/dogleg_test.cc31
-rw-r--r--intern/libmv/libmv/numeric/function_derivative.h17
-rw-r--r--intern/libmv/libmv/numeric/function_derivative_test.cc18
-rw-r--r--intern/libmv/libmv/numeric/levenberg_marquardt.h70
-rw-r--r--intern/libmv/libmv/numeric/levenberg_marquardt_test.cc10
-rw-r--r--intern/libmv/libmv/numeric/numeric.cc36
-rw-r--r--intern/libmv/libmv/numeric/numeric.h393
-rw-r--r--intern/libmv/libmv/numeric/numeric_test.cc92
-rw-r--r--intern/libmv/libmv/numeric/poly.h29
-rw-r--r--intern/libmv/libmv/numeric/poly_test.cc26
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.cc458
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.h35
-rw-r--r--intern/libmv/libmv/simple_pipeline/callbacks.h2
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc279
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.h104
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h143
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc129
-rw-r--r--intern/libmv/libmv/simple_pipeline/detect.cc172
-rw-r--r--intern/libmv/libmv/simple_pipeline/detect.h17
-rw-r--r--intern/libmv/libmv/simple_pipeline/detect_test.cc19
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.cc193
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.h129
-rw-r--r--intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc42
-rw-r--r--intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h29
-rw-r--r--intern/libmv/libmv/simple_pipeline/intersect.cc82
-rw-r--r--intern/libmv/libmv/simple_pipeline/intersect.h16
-rw-r--r--intern/libmv/libmv/simple_pipeline/intersect_test.cc18
-rw-r--r--intern/libmv/libmv/simple_pipeline/keyframe_selection.cc107
-rw-r--r--intern/libmv/libmv/simple_pipeline/keyframe_selection.h9
-rw-r--r--intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc478
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver.cc59
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver.h10
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver_test.cc31
-rw-r--r--intern/libmv/libmv/simple_pipeline/packed_intrinsics.h18
-rw-r--r--intern/libmv/libmv/simple_pipeline/pipeline.cc192
-rw-r--r--intern/libmv/libmv/simple_pipeline/pipeline.h31
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction.cc67
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction.h41
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc6
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction_scale.h2
-rw-r--r--intern/libmv/libmv/simple_pipeline/resect.cc80
-rw-r--r--intern/libmv/libmv/simple_pipeline/resect.h11
-rw-r--r--intern/libmv/libmv/simple_pipeline/resect_test.cc4
-rw-r--r--intern/libmv/libmv/simple_pipeline/tracks.cc30
-rw-r--r--intern/libmv/libmv/simple_pipeline/tracks.h16
-rw-r--r--intern/libmv/libmv/threading/threading.h2
-rw-r--r--intern/libmv/libmv/tracking/brute_region_tracker.cc195
-rw-r--r--intern/libmv/libmv/tracking/brute_region_tracker.h14
-rw-r--r--intern/libmv/libmv/tracking/hybrid_region_tracker.cc12
-rw-r--r--intern/libmv/libmv/tracking/hybrid_region_tracker.h19
-rw-r--r--intern/libmv/libmv/tracking/kalman_filter.h68
-rw-r--r--intern/libmv/libmv/tracking/klt_region_tracker.cc63
-rw-r--r--intern/libmv/libmv/tracking/klt_region_tracker.h10
-rw-r--r--intern/libmv/libmv/tracking/pyramid_region_tracker.cc19
-rw-r--r--intern/libmv/libmv/tracking/pyramid_region_tracker.h15
-rw-r--r--intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc10
-rw-r--r--intern/libmv/libmv/tracking/region_tracker.h10
-rw-r--r--intern/libmv/libmv/tracking/retrack_region_tracker.cc10
-rw-r--r--intern/libmv/libmv/tracking/retrack_region_tracker.h15
-rw-r--r--intern/libmv/libmv/tracking/track_region.cc623
-rw-r--r--intern/libmv/libmv/tracking/track_region.h44
-rw-r--r--intern/libmv/libmv/tracking/trklt_region_tracker.cc63
-rw-r--r--intern/libmv/libmv/tracking/trklt_region_tracker.h10
-rw-r--r--intern/opencolorio/ocio_impl.cc14
-rw-r--r--intern/utfconv/utfconv.h24
-rw-r--r--release/datafiles/colormanagement/config.ocio1
-rw-r--r--release/datafiles/colormanagement/luts/xyz_D65_to_E.spimtx3
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default.c1
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c32
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py3
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_rtl.py3
-rw-r--r--release/scripts/modules/bl_previews_utils/bl_previews_render.py3
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py4
-rw-r--r--release/scripts/modules/bpy_types.py8
-rw-r--r--release/scripts/modules/console_python.py13
-rw-r--r--release/scripts/modules/rna_info.py4
-rw-r--r--release/scripts/presets/framerate/120.py3
-rw-r--r--release/scripts/presets/framerate/240.py3
-rw-r--r--release/scripts/presets/interface_theme/Blender_Light.xml36
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py80
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py19
-rw-r--r--release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py1
-rw-r--r--release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/anim.py2
-rw-r--r--release/scripts/startup/bl_operators/console.py1
-rw-r--r--release/scripts/startup/bl_operators/geometry_nodes.py6
-rw-r--r--release/scripts/startup/bl_operators/object_align.py1
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py1
-rw-r--r--release/scripts/startup/bl_operators/presets.py2
-rw-r--r--release/scripts/startup/bl_operators/spreadsheet.py52
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py1
-rw-r--r--release/scripts/startup/bl_operators/view3d.py2
-rw-r--r--release/scripts/startup/bl_operators/wm.py13
-rw-r--r--release/scripts/startup/bl_ui/__init__.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_collection.py100
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py10
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_hair.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_data_pointcloud.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_shaderfx.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_volume.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_lineart.py59
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py33
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py6
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py17
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py1
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py2
-rw-r--r--release/scripts/startup/bl_ui/space_image.py5
-rw-r--r--release/scripts/startup/bl_ui/space_node.py1
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py7
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py26
-rw-r--r--release/scripts/startup/bl_ui/space_spreadsheet.py57
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py19
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py4
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py17
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py91
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py16
-rw-r--r--release/scripts/startup/nodeitems_builtins.py27
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/BKE_animsys.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h8
-rw-r--r--source/blender/blenkernel/BKE_attribute.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h53
-rw-r--r--source/blender/blenkernel/BKE_collection.h3
-rw-r--r--source/blender/blenkernel/BKE_context.h1
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h11
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh16
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h10
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh28
-rw-r--r--source/blender/blenkernel/BKE_global.h23
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h5
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h3
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h15
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h10
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h9
-rw-r--r--source/blender/blenkernel/BKE_main.h16
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_mirror.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h50
-rw-r--r--source/blender/blenkernel/BKE_node_ui_storage.hh27
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/intern/armature_pose.cc133
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc1546
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh494
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c7
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c21
-rw-r--r--source/blender/blenkernel/intern/blendfile.c144
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c47
-rw-r--r--source/blender/blenkernel/intern/context.c9
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc99
-rw-r--r--source/blender/blenkernel/intern/cryptomatte_test.cc52
-rw-r--r--source/blender/blenkernel/intern/displist.c12
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc173
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc979
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc205
-rw-r--r--source/blender/blenkernel/intern/geometry_component_volume.cc100
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc439
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc13
-rw-r--r--source/blender/blenkernel/intern/gpencil.c40
-rw-r--r--source/blender/blenkernel/intern/idtype.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c11
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c20
-rw-r--r--source/blender/blenkernel/intern/lib_override.c372
-rw-r--r--source/blender/blenkernel/intern/lib_query.c17
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c41
-rw-r--r--source/blender/blenkernel/intern/main.c23
-rw-r--r--source/blender/blenkernel/intern/main_idmap.c10
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc115
-rw-r--r--source/blender/blenkernel/intern/node.cc161
-rw-r--r--source/blender/blenkernel/intern/node_ui_storage.cc13
-rw-r--r--source/blender/blenkernel/intern/object_update.c10
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c10
-rw-r--r--source/blender/blenkernel/intern/pbvh.c9
-rw-r--r--source/blender/blenkernel/intern/scene.c5
-rw-r--r--source/blender/blenkernel/intern/screen.c24
-rw-r--r--source/blender/blenkernel/intern/simulation.cc1
-rw-r--r--source/blender/blenkernel/intern/sound.c4
-rw-r--r--source/blender/blenkernel/intern/studiolight.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c3
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c9
-rw-r--r--source/blender/blenkernel/tracking_private.h1
-rw-r--r--source/blender/blenlib/BLI_array_utils.h8
-rw-r--r--source/blender/blenlib/BLI_float2.hh5
-rw-r--r--source/blender/blenlib/BLI_float3.hh5
-rw-r--r--source/blender/blenlib/BLI_hash.hh9
-rw-r--r--source/blender/blenlib/BLI_linear_allocator.hh50
-rw-r--r--source/blender/blenlib/BLI_math_base.h3
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h1
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh45
-rw-r--r--source/blender/blenlib/BLI_mesh_boolean.hh2
-rw-r--r--source/blender/blenlib/BLI_multi_value_map.hh16
-rw-r--r--source/blender/blenlib/BLI_resource_collector.hh7
-rw-r--r--source/blender/blenlib/BLI_span.hh37
-rw-r--r--source/blender/blenlib/BLI_string_utils.h2
-rw-r--r--source/blender/blenlib/BLI_vector.hh10
-rw-r--r--source/blender/blenlib/intern/array_utils.c97
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c12
-rw-r--r--source/blender/blenlib/intern/math_matrix.c10
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc209
-rw-r--r--source/blender/blenlib/intern/storage.c2
-rw-r--r--source/blender/blenlib/intern/string_search.cc17
-rw-r--r--source/blender/blenlib/intern/string_utils.c33
-rw-r--r--source/blender/blenlib/tests/BLI_linear_allocator_test.cc23
-rw-r--r--source/blender/blenlib/tests/BLI_map_test.cc22
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_boolean_test.cc79
-rw-r--r--source/blender/blenlib/tests/BLI_multi_value_map_test.cc21
-rw-r--r--source/blender/blenlib/tests/BLI_span_test.cc29
-rw-r--r--source/blender/blenloader/BLO_readfile.h6
-rw-r--r--source/blender/blenloader/intern/blend_validate.c2
-rw-r--r--source/blender/blenloader/intern/readfile.c116
-rw-r--r--source/blender/blenloader/intern/readfile.h12
-rw-r--r--source/blender/blenloader/intern/versioning_250.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c2
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c130
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c3
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c13
-rw-r--r--source/blender/blenloader/intern/writefile.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c123
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_private.h7
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c24
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc9
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h2
-rw-r--r--source/blender/compositor/CMakeLists.txt444
-rw-r--r--source/blender/compositor/COM_compositor.h6
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.cc (renamed from source/blender/compositor/intern/COM_CPUDevice.cpp)4
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrder.cc (renamed from source/blender/compositor/intern/COM_ChunkOrder.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrderHotspot.cc (renamed from source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp)13
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrderHotspot.h5
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.cc (renamed from source/blender/compositor/intern/COM_CompositorContext.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc (renamed from source/blender/compositor/intern/COM_Converter.cpp)34
-rw-r--r--source/blender/compositor/intern/COM_Converter.h79
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc (renamed from source/blender/compositor/intern/COM_Debug.cpp)69
-rw-r--r--source/blender/compositor/intern/COM_Device.cc (renamed from source/blender/compositor/intern/COM_Device.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Device.h2
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cc (renamed from source/blender/compositor/intern/COM_ExecutionGroup.cpp)229
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h55
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc (renamed from source/blender/compositor/intern/COM_ExecutionSystem.cpp)48
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h27
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc (renamed from source/blender/compositor/intern/COM_MemoryBuffer.cpp)11
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h5
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cc (renamed from source/blender/compositor/intern/COM_MemoryProxy.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_MetaData.cc (renamed from source/blender/compositor/intern/COM_MetaData.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_MetaData.h1
-rw-r--r--source/blender/compositor/intern/COM_Node.cc (renamed from source/blender/compositor/intern/COM_Node.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Node.h11
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.cc (renamed from source/blender/compositor/intern/COM_NodeConverter.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.cc (renamed from source/blender/compositor/intern/COM_NodeGraph.cpp)16
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.h26
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc (renamed from source/blender/compositor/intern/COM_NodeOperation.cpp)11
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h8
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc (renamed from source/blender/compositor/intern/COM_NodeOperationBuilder.cpp)175
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h30
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cc (renamed from source/blender/compositor/intern/COM_OpenCLDevice.cpp)10
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h8
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.cc (renamed from source/blender/compositor/intern/COM_SingleThreadedOperation.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.h2
-rw-r--r--source/blender/compositor/intern/COM_SocketReader.cc (renamed from source/blender/compositor/intern/COM_SocketReader.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.cc (renamed from source/blender/compositor/intern/COM_WorkPackage.cpp)6
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.h30
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cc (renamed from source/blender/compositor/intern/COM_WorkScheduler.cpp)8
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc (renamed from source/blender/compositor/intern/COM_compositor.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_AlphaOverNode.cc (renamed from source/blender/compositor/nodes/COM_AlphaOverNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BilateralBlurNode.cc (renamed from source/blender/compositor/nodes/COM_BilateralBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BlurNode.cc (renamed from source/blender/compositor/nodes/COM_BlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BokehBlurNode.cc (renamed from source/blender/compositor/nodes/COM_BokehBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BokehImageNode.cc (renamed from source/blender/compositor/nodes/COM_BokehImageNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BoxMaskNode.cc (renamed from source/blender/compositor/nodes/COM_BoxMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cc (renamed from source/blender/compositor/nodes/COM_BrightnessNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ChannelMatteNode.cc (renamed from source/blender/compositor/nodes/COM_ChannelMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ChromaMatteNode.cc (renamed from source/blender/compositor/nodes/COM_ChromaMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cc (renamed from source/blender/compositor/nodes/COM_ColorBalanceNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorCorrectionNode.cc (renamed from source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorCurveNode.cc (renamed from source/blender/compositor/nodes/COM_ColorCurveNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorExposureNode.cc (renamed from source/blender/compositor/nodes/COM_ColorExposureNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorMatteNode.cc (renamed from source/blender/compositor/nodes/COM_ColorMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorNode.cc (renamed from source/blender/compositor/nodes/COM_ColorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorRampNode.cc (renamed from source/blender/compositor/nodes/COM_ColorRampNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorSpillNode.cc (renamed from source/blender/compositor/nodes/COM_ColorSpillNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorToBWNode.cc (renamed from source/blender/compositor/nodes/COM_ColorToBWNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cc (renamed from source/blender/compositor/nodes/COM_CombineColorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.cc (renamed from source/blender/compositor/nodes/COM_CompositorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ConvertAlphaNode.cc (renamed from source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cc (renamed from source/blender/compositor/nodes/COM_CornerPinNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CropNode.cc (renamed from source/blender/compositor/nodes/COM_CropNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc263
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cpp80
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.h62
-rw-r--r--source/blender/compositor/nodes/COM_DefocusNode.cc (renamed from source/blender/compositor/nodes/COM_DefocusNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.cc (renamed from source/blender/compositor/nodes/COM_DenoiseNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DespeckleNode.cc (renamed from source/blender/compositor/nodes/COM_DespeckleNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DifferenceMatteNode.cc (renamed from source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DilateErodeNode.cc (renamed from source/blender/compositor/nodes/COM_DilateErodeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DirectionalBlurNode.cc (renamed from source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DisplaceNode.cc (renamed from source/blender/compositor/nodes/COM_DisplaceNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DistanceMatteNode.cc (renamed from source/blender/compositor/nodes/COM_DistanceMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc (renamed from source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_EllipseMaskNode.cc (renamed from source/blender/compositor/nodes/COM_EllipseMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cc (renamed from source/blender/compositor/nodes/COM_FilterNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_FlipNode.cc (renamed from source/blender/compositor/nodes/COM_FlipNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_GammaNode.cc (renamed from source/blender/compositor/nodes/COM_GammaNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_GlareNode.cc (renamed from source/blender/compositor/nodes/COM_GlareNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc (renamed from source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cc (renamed from source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_IDMaskNode.cc (renamed from source/blender/compositor/nodes/COM_IDMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cc (renamed from source/blender/compositor/nodes/COM_ImageNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h2
-rw-r--r--source/blender/compositor/nodes/COM_InpaintNode.cc (renamed from source/blender/compositor/nodes/COM_InpaintNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_InvertNode.cc (renamed from source/blender/compositor/nodes/COM_InvertNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_KeyingNode.cc (renamed from source/blender/compositor/nodes/COM_KeyingNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.cc (renamed from source/blender/compositor/nodes/COM_KeyingScreenNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_LensDistortionNode.cc (renamed from source/blender/compositor/nodes/COM_LensDistortionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.cc (renamed from source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MapRangeNode.cc (renamed from source/blender/compositor/nodes/COM_MapRangeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MapUVNode.cc (renamed from source/blender/compositor/nodes/COM_MapUVNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MapValueNode.cc (renamed from source/blender/compositor/nodes/COM_MapValueNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MaskNode.cc (renamed from source/blender/compositor/nodes/COM_MaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cc (renamed from source/blender/compositor/nodes/COM_MathNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MixNode.cc (renamed from source/blender/compositor/nodes/COM_MixNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cc (renamed from source/blender/compositor/nodes/COM_MovieClipNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MovieDistortionNode.cc (renamed from source/blender/compositor/nodes/COM_MovieDistortionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_NormalNode.cc (renamed from source/blender/compositor/nodes/COM_NormalNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_NormalizeNode.cc (renamed from source/blender/compositor/nodes/COM_NormalizeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc (renamed from source/blender/compositor/nodes/COM_OutputFileNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_PixelateNode.cc (renamed from source/blender/compositor/nodes/COM_PixelateNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc (renamed from source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cc (renamed from source/blender/compositor/nodes/COM_RenderLayersNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_RotateNode.cc (renamed from source/blender/compositor/nodes/COM_RotateNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ScaleNode.cc (renamed from source/blender/compositor/nodes/COM_ScaleNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cc (renamed from source/blender/compositor/nodes/COM_SeparateColorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SetAlphaNode.cc (renamed from source/blender/compositor/nodes/COM_SetAlphaNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cc (renamed from source/blender/compositor/nodes/COM_SocketProxyNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cc (renamed from source/blender/compositor/nodes/COM_SplitViewerNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_Stabilize2dNode.cc (renamed from source/blender/compositor/nodes/COM_Stabilize2dNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.cc (renamed from source/blender/compositor/nodes/COM_SunBeamsNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.cc (renamed from source/blender/compositor/nodes/COM_SwitchNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.cc (renamed from source/blender/compositor/nodes/COM_SwitchViewNode.cpp)2
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.cc (renamed from source/blender/compositor/nodes/COM_TextureNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TimeNode.cc (renamed from source/blender/compositor/nodes/COM_TimeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TonemapNode.cc (renamed from source/blender/compositor/nodes/COM_TonemapNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.cc (renamed from source/blender/compositor/nodes/COM_TrackPositionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TransformNode.cc (renamed from source/blender/compositor/nodes/COM_TransformNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.cc (renamed from source/blender/compositor/nodes/COM_TranslateNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ValueNode.cc (renamed from source/blender/compositor/nodes/COM_ValueNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_VectorBlurNode.cc (renamed from source/blender/compositor/nodes/COM_VectorBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_VectorCurveNode.cc (renamed from source/blender/compositor/nodes/COM_VectorCurveNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ViewLevelsNode.cc (renamed from source/blender/compositor/nodes/COM_ViewLevelsNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cc (renamed from source/blender/compositor/nodes/COM_ViewerNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ZCombineNode.cc (renamed from source/blender/compositor/nodes/COM_ZCombineNode.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc (renamed from source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc (renamed from source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc (renamed from source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cc (renamed from source/blender/compositor/operations/COM_AntiAliasOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.cc (renamed from source/blender/compositor/operations/COM_BilateralBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cc (renamed from source/blender/compositor/operations/COM_BlurBaseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cc (renamed from source/blender/compositor/operations/COM_BokehBlurOperation.cpp)22
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.cc (renamed from source/blender/compositor/operations/COM_BokehImageOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BoxMaskOperation.cc (renamed from source/blender/compositor/operations/COM_BoxMaskOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cc (renamed from source/blender/compositor/operations/COM_BrightnessOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cc (renamed from source/blender/compositor/operations/COM_CalculateMeanOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc (renamed from source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cc (renamed from source/blender/compositor/operations/COM_ChangeHSVOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.cc (renamed from source/blender/compositor/operations/COM_ChannelMatteOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ChromaMatteOperation.cc (renamed from source/blender/compositor/operations/COM_ChromaMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc (renamed from source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc (renamed from source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cc (renamed from source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cc (renamed from source/blender/compositor/operations/COM_ColorCurveOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorExposureOperation.cc (renamed from source/blender/compositor/operations/COM_ColorExposureOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorMatteOperation.cc (renamed from source/blender/compositor/operations/COM_ColorMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.cc (renamed from source/blender/compositor/operations/COM_ColorRampOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorSpillOperation.cc (renamed from source/blender/compositor/operations/COM_ColorSpillOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cc (renamed from source/blender/compositor/operations/COM_CompositorOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc (renamed from source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc (renamed from source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cc (renamed from source/blender/compositor/operations/COM_ConvertOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc (renamed from source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc (renamed from source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc (renamed from source/blender/compositor/operations/COM_CropOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.cc (renamed from source/blender/compositor/operations/COM_CryptomatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.cc (renamed from source/blender/compositor/operations/COM_CurveBaseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cc (renamed from source/blender/compositor/operations/COM_DenoiseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DespeckleOperation.cc (renamed from source/blender/compositor/operations/COM_DespeckleOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_DifferenceMatteOperation.cc (renamed from source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cc (renamed from source/blender/compositor/operations/COM_DilateErodeOperation.cpp)96
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cc (renamed from source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cc (renamed from source/blender/compositor/operations/COM_DisplaceOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc (renamed from source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc (renamed from source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc (renamed from source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DotproductOperation.cc (renamed from source/blender/compositor/operations/COM_DotproductOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc (renamed from source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.cc (renamed from source/blender/compositor/operations/COM_EllipseMaskOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc (renamed from source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.cc (renamed from source/blender/compositor/operations/COM_FlipOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GammaCorrectOperation.cc (renamed from source/blender/compositor/operations/COM_GammaCorrectOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GammaOperation.cc (renamed from source/blender/compositor/operations/COM_GammaOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.cc (renamed from source/blender/compositor/operations/COM_GlareBaseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cc (renamed from source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cc (renamed from source/blender/compositor/operations/COM_GlareGhostOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc (renamed from source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cc (renamed from source/blender/compositor/operations/COM_GlareStreaksOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cc (renamed from source/blender/compositor/operations/COM_GlareThresholdOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc (renamed from source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.cc (renamed from source/blender/compositor/operations/COM_IDMaskOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cc (renamed from source/blender/compositor/operations/COM_ImageOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cc (renamed from source/blender/compositor/operations/COM_InpaintOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_InvertOperation.cc (renamed from source/blender/compositor/operations/COM_InvertOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingBlurOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingClipOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_KeyingDespillOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingDespillOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_KeyingOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingScreenOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cc (renamed from source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_MapRangeOperation.cc (renamed from source/blender/compositor/operations/COM_MapRangeOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cc (renamed from source/blender/compositor/operations/COM_MapUVOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MapValueOperation.cc (renamed from source/blender/compositor/operations/COM_MapValueOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cc (renamed from source/blender/compositor/operations/COM_MaskOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cc (renamed from source/blender/compositor/operations/COM_MathBaseOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc (renamed from source/blender/compositor/operations/COM_MixOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc (renamed from source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cc (renamed from source/blender/compositor/operations/COM_MovieClipOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cc (renamed from source/blender/compositor/operations/COM_MovieDistortionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cc (renamed from source/blender/compositor/operations/COM_MultilayerImageOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cc (renamed from source/blender/compositor/operations/COM_NormalizeOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc (renamed from source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc (renamed from source/blender/compositor/operations/COM_OutputFileOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PixelateOperation.cc (renamed from source/blender/compositor/operations/COM_PixelateOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc (renamed from source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc (renamed from source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cc (renamed from source/blender/compositor/operations/COM_PlaneTrackOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cc (renamed from source/blender/compositor/operations/COM_PreviewOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc (renamed from source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_QualityStepHelper.cc (renamed from source/blender/compositor/operations/COM_QualityStepHelper.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.cc (renamed from source/blender/compositor/operations/COM_ReadBufferOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc (renamed from source/blender/compositor/operations/COM_RenderLayersProg.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.cc (renamed from source/blender/compositor/operations/COM_RotateOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc (renamed from source/blender/compositor/operations/COM_ScaleOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc (renamed from source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc (renamed from source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc (renamed from source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cc (renamed from source/blender/compositor/operations/COM_SetColorOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetSamplerOperation.cc (renamed from source/blender/compositor/operations/COM_SetSamplerOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cc (renamed from source/blender/compositor/operations/COM_SetValueOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cc (renamed from source/blender/compositor/operations/COM_SetVectorOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SocketProxyOperation.cc (renamed from source/blender/compositor/operations/COM_SocketProxyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cc (renamed from source/blender/compositor/operations/COM_SplitOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cc (renamed from source/blender/compositor/operations/COM_SunBeamsOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc (renamed from source/blender/compositor/operations/COM_TextureOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cc (renamed from source/blender/compositor/operations/COM_TonemapOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cc (renamed from source/blender/compositor/operations/COM_TrackPositionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc (renamed from source/blender/compositor/operations/COM_TranslateOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc (renamed from source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp)32
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc (renamed from source/blender/compositor/operations/COM_VectorBlurOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.cc (renamed from source/blender/compositor/operations/COM_VectorCurveOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc (renamed from source/blender/compositor/operations/COM_ViewerOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.cc (renamed from source/blender/compositor/operations/COM_WrapOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cc (renamed from source/blender/compositor/operations/COM_WriteBufferOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_ZCombineOperation.cc (renamed from source/blender/compositor/operations/COM_ZCombineOperation.cpp)4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h8
-rw-r--r--source/blender/draw/CMakeLists.txt5
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c174
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c73
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c36
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h63
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c116
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c179
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c12
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl126
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl58
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl144
-rw-r--r--source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl23
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl12
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl19
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl30
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl59
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl58
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_reflection_lib.glsl101
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl220
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl149
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl594
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl20
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl36
-rw-r--r--source/blender/draw/engines/eevee/shaders/random_lib.glsl38
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl393
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/ssr_lib.glsl38
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl7
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c5
-rw-r--r--source/blender/draw/intern/draw_cache.c9
-rw-r--r--source/blender/draw/intern/draw_manager.h4
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c92
-rw-r--r--source/blender/draw/intern/shaders/common_math_geom_lib.glsl17
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl6
-rw-r--r--source/blender/draw/tests/shaders_test.cc8
-rw-r--r--source/blender/editors/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c4
-rw-r--r--source/blender/editors/animation/anim_markers.c22
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c23
-rw-r--r--source/blender/editors/animation/keyframes_draw.c310
-rw-r--r--source/blender/editors/armature/armature_relations.c13
-rw-r--r--source/blender/editors/armature/armature_select.c17
-rw-r--r--source/blender/editors/armature/pose_edit.c4
-rw-r--r--source/blender/editors/armature/pose_lib.c4
-rw-r--r--source/blender/editors/armature/pose_slide.c6
-rw-r--r--source/blender/editors/curve/editcurve.c4
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt1
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_add_lineart.c120
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_edit_curve.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c52
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c33
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c27
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c13
-rw-r--r--source/blender/editors/include/ED_anim_api.h1
-rw-r--r--source/blender/editors/include/ED_clip.h4
-rw-r--r--source/blender/editors/include/ED_fileselect.h7
-rw-r--r--source/blender/editors/include/ED_gpencil.h1
-rw-r--r--source/blender/editors/include/ED_image.h4
-rw-r--r--source/blender/editors/include/ED_node.h5
-rw-r--r--source/blender/editors/include/ED_object.h4
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_space_api.h1
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface_context_menu.c8
-rw-r--r--source/blender/editors/interface/interface_draw.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c35
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c231
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h7
-rw-r--r--source/blender/editors/interface/interface_handlers.c28
-rw-r--r--source/blender/editors/interface/interface_intern.h4
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c14
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c1
-rw-r--r--source/blender/editors/interface/interface_templates.c14
-rw-r--r--source/blender/editors/interface/interface_widgets.c32
-rw-r--r--source/blender/editors/interface/resources.c3
-rw-r--r--source/blender/editors/io/io_cache.c4
-rw-r--r--source/blender/editors/mesh/editmesh_add.c15
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c13
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c4
-rw-r--r--source/blender/editors/mesh/editmesh_select.c12
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c16
-rw-r--r--source/blender/editors/mesh/mesh_intern.h2
-rw-r--r--source/blender/editors/mesh/mesh_ops.c2
-rw-r--r--source/blender/editors/object/object_add.c85
-rw-r--r--source/blender/editors/object/object_bake.c2
-rw-r--r--source/blender/editors/object/object_bake_api.c11
-rw-r--r--source/blender/editors/object/object_edit.c4
-rw-r--r--source/blender/editors/object/object_ops.c5
-rw-r--r--source/blender/editors/object/object_relations.c12
-rw-r--r--source/blender/editors/render/render_internal.c4
-rw-r--r--source/blender/editors/render/render_preview.c2
-rw-r--r--source/blender/editors/render/render_shading.c7
-rw-r--r--source/blender/editors/screen/screen_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c24
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c441
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c19
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c355
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c323
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c27
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_init.c195
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c37
-rw-r--r--source/blender/editors/space_action/action_data.c4
-rw-r--r--source/blender/editors/space_api/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_api/spacetypes.c3
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c31
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c10
-rw-r--r--source/blender/editors/space_clip/clip_editor.c17
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c2
-rw-r--r--source/blender/editors/space_file/file_intern.h16
-rw-r--r--source/blender/editors/space_file/file_ops.c105
-rw-r--r--source/blender/editors/space_file/filelist.c74
-rw-r--r--source/blender/editors/space_file/filelist.h3
-rw-r--r--source/blender/editors/space_file/filesel.c60
-rw-r--r--source/blender/editors/space_file/space_file.c77
-rw-r--r--source/blender/editors/space_graph/graph_draw.c139
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c6
-rw-r--r--source/blender/editors/space_image/image_ops.c21
-rw-r--r--source/blender/editors/space_image/image_undo.c5
-rw-r--r--source/blender/editors/space_nla/nla_channels.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c154
-rw-r--r--source/blender/editors/space_node/node_add.c301
-rw-r--r--source/blender/editors/space_node/node_draw.cc74
-rw-r--r--source/blender/editors/space_node/node_edit.c30
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc26
-rw-r--r--source/blender/editors/space_node/node_group.c3
-rw-r--r--source/blender/editors/space_node/node_intern.h21
-rw-r--r--source/blender/editors/space_node/node_ops.c4
-rw-r--r--source/blender/editors/space_node/node_relationships.c229
-rw-r--r--source/blender/editors/space_node/node_templates.c21
-rw-r--r--source/blender/editors/space_node/node_view.c26
-rw-r--r--source/blender/editors/space_node/space_node.c39
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt20
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c12
-rw-r--r--source/blender/editors/space_outliner/outliner_context.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c20
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c62
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c23
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c25
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c62
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c196
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc14
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc84
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.h3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh28
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.cc44
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.hh36
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.cc (renamed from source/blender/editors/space_outliner/tree/tree_element_driver_base.cc)2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.hh (renamed from source/blender/editors/space_outliner/tree/tree_element_driver_base.hh)0
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh34
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc135
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.hh55
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.hh34
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.cc74
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.hh43
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_nla.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_nla.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc84
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh49
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc50
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh36
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.cc51
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.hh36
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c59
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c29
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_proxy.c89
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt50
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc364
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc189
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh97
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_draw.cc304
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_draw.hh60
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc380
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh34
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh25
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc21
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c5
-rw-r--r--source/blender/editors/transform/transform.h14
-rw-r--r--source/blender/editors/transform/transform_constraints.c7
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c11
-rw-r--r--source/blender/editors/transform/transform_ops.c5
-rw-r--r--source/blender/editors/undo/ed_undo.c66
-rw-r--r--source/blender/editors/util/ed_draw.c2
-rw-r--r--source/blender/editors/util/ed_util_ops.cc4
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c5
-rw-r--r--source/blender/functions/CMakeLists.txt3
-rw-r--r--source/blender/functions/FN_attributes_ref.hh341
-rw-r--r--source/blender/functions/FN_cpp_type.hh6
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh57
-rw-r--r--source/blender/functions/intern/attributes_ref.cc78
-rw-r--r--source/blender/functions/intern/multi_function_network.cc4
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc36
-rw-r--r--source/blender/functions/tests/FN_attributes_ref_test.cc97
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt12
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_lineart.h31
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c17
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c501
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h552
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c987
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c3929
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h113
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c439
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_util.c233
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc2
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl2
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h1
-rw-r--r--source/blender/imbuf/intern/indexer.c37
-rw-r--r--source/blender/makesdna/DNA_ID.h44
-rw-r--r--source/blender/makesdna/DNA_collection_types.h16
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h13
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h73
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h3
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h70
-rw-r--r--source/blender/makesdna/DNA_material_types.h11
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_node_types.h77
-rw-r--r--source/blender/makesdna/DNA_object_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_object_types.h31
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h10
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h11
-rw-r--r--source/blender/makesdna/DNA_space_types.h59
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h13
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h27
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c3
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/makesrna/RNA_access.h17
-rw-r--r--source/blender/makesrna/RNA_define.h7
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt13
-rw-r--r--source/blender/makesrna/intern/makesrna.c8
-rw-r--r--source/blender/makesrna/intern/rna_ID.c3
-rw-r--r--source/blender/makesrna/intern/rna_access.c29
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c171
-rw-r--r--source/blender/makesrna/intern/rna_armature.c9
-rw-r--r--source/blender/makesrna/intern/rna_brush.c3
-rw-r--r--source/blender/makesrna/intern/rna_collection.c31
-rw-r--r--source/blender/makesrna/intern/rna_define.c35
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c287
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_material.c78
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c18
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c356
-rw-r--r--source/blender/makesrna/intern/rna_object.c88
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c52
-rw-r--r--source/blender/makesrna/intern/rna_rna.c21
-rw-r--r--source/blender/makesrna/intern/rna_scene.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c220
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c21
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c71
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c5
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c85
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc291
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c16
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c24
-rw-r--r--source/blender/nodes/CMakeLists.txt18
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh557
-rw-r--r--source/blender/nodes/NOD_geometry.h12
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh24
-rw-r--r--source/blender/nodes/NOD_node_tree_dependencies.hh76
-rw-r--r--source/blender/nodes/NOD_node_tree_multi_function.hh107
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh167
-rw-r--r--source/blender/nodes/NOD_static_types.h15
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c157
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc350
-rw-r--r--source/blender/nodes/function/nodes/node_fn_group_instance_id.cc7
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_float.cc11
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc12
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc164
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc87
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc244
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc279
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc84
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc103
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc91
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc188
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc183
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc131
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc507
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_translate.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc)24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc12
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc644
-rw-r--r--source/blender/nodes/intern/node_exec.c19
-rw-r--r--source/blender/nodes/intern/node_exec.h2
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc17
-rw-r--r--source/blender/nodes/intern/node_socket.cc1
-rw-r--r--source/blender/nodes/intern/node_tree_dependencies.cc57
-rw-r--r--source/blender/nodes/intern/node_tree_multi_function.cc281
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc144
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c4
-rw-r--r--source/blender/nodes/shader/node_shader_util.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.c80
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc217
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c18
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c33
-rw-r--r--source/blender/python/gpu/gpu_py_element.c9
-rw-r--r--source/blender/python/gpu/gpu_py_framebuffer.c10
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c24
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c10
-rw-r--r--source/blender/python/gpu/gpu_py_state.c73
-rw-r--r--source/blender/python/gpu/gpu_py_texture.c38
-rw-r--r--source/blender/python/gpu/gpu_py_uniformbuffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.c4
-rw-r--r--source/blender/python/intern/CMakeLists.txt14
-rw-r--r--source/blender/python/intern/bpy.c3
-rw-r--r--source/blender/python/intern/bpy_app.c2
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c4
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c21
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c4
-rw-r--r--source/blender/python/intern/bpy_app_ocio.c4
-rw-r--r--source/blender/python/intern/bpy_app_oiio.c4
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c4
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.c4
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c4
-rw-r--r--source/blender/python/intern/bpy_app_usd.c4
-rw-r--r--source/blender/python/intern/bpy_interface.c6
-rw-r--r--source/blender/python/intern/bpy_library_load.c39
-rw-r--r--source/blender/python/intern/bpy_library_write.c6
-rw-r--r--source/blender/python/intern/bpy_operator.c10
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c10
-rw-r--r--source/blender/python/intern/bpy_props.c949
-rw-r--r--source/blender/python/intern/bpy_props.h1
-rw-r--r--source/blender/python/intern/bpy_rna.c169
-rw-r--r--source/blender/python/intern/bpy_rna_data.c219
-rw-r--r--source/blender/python/intern/bpy_rna_data.h29
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c7
-rw-r--r--source/blender/render/intern/multires_bake.c16
-rw-r--r--source/blender/render/intern/texture_procedural.c40
-rw-r--r--source/blender/sequencer/CMakeLists.txt1
-rw-r--r--source/blender/sequencer/SEQ_add.h1
-rw-r--r--source/blender/sequencer/SEQ_proxy.h14
-rw-r--r--source/blender/sequencer/SEQ_render.h1
-rw-r--r--source/blender/sequencer/intern/proxy.c54
-rw-r--r--source/blender/sequencer/intern/proxy_job.c121
-rw-r--r--source/blender/sequencer/intern/render.c5
-rw-r--r--source/blender/sequencer/intern/sequencer.c6
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.c17
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/WM_types.h9
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c3
-rw-r--r--source/blender/windowmanager/intern/wm.c21
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c28
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c4
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c284
-rw-r--r--source/blender/windowmanager/intern/wm_files.c296
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c5
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c2
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c97
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c4
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.c10
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c4
-rw-r--r--source/blender/windowmanager/intern/wm_window.c16
-rw-r--r--source/blender/windowmanager/wm.h7
-rw-r--r--source/blender/windowmanager/wm_cursors.h1
-rw-r--r--source/blender/windowmanager/wm_window.h4
-rw-r--r--source/creator/creator.c12
-rw-r--r--source/creator/creator_args.c11
m---------source/tools0
-rw-r--r--tests/gtests/runner/CMakeLists.txt1
-rw-r--r--tests/python/CMakeLists.txt6
-rw-r--r--tests/python/bl_blendfile_io.py6
-rw-r--r--tests/python/bl_blendfile_liblink.py9
-rw-r--r--tests/python/bl_keymap_validate.py241
1188 files changed, 36585 insertions, 16324 deletions
diff --git a/.clang-format b/.clang-format
index 8a992fea3a9..79aa893cada 100644
--- a/.clang-format
+++ b/.clang-format
@@ -161,6 +161,7 @@ PenaltyBreakString: 1000000
# "^\s+[A-Z][A-Z0-9_]+\s*\([^\n]*\)\n\s*\{"
ForEachMacros:
- BEGIN_ANIMFILTER_SUBCHANNELS
+ - BKE_pbvh_vertex_iter_begin
- BLI_FOREACH_SPARSE_RANGE
- BLI_SMALLSTACK_ITER_BEGIN
- BMO_ITER
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ddfce0a48d9..5f30b946aca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -300,15 +300,33 @@ option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.or
# Sound output
option(WITH_SDL "Enable SDL for sound and joystick support" ON)
option(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON)
+if(APPLE)
+ option(WITH_COREAUDIO "Enable CoreAudio for audio support on macOS" ON)
+else()
+ set(WITH_COREAUDIO OFF)
+endif()
if(NOT WIN32)
option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ON)
if(UNIX AND NOT APPLE)
option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
endif()
+else()
+ set(WITH_JACK OFF)
endif()
if(UNIX AND NOT APPLE)
option(WITH_SDL_DYNLOAD "Enable runtime dynamic SDL libraries loading" OFF)
endif()
+if(UNIX AND NOT APPLE)
+ option(WITH_PULSEAUDIO "Enable PulseAudio for audio support on Linux" ON)
+ option(WITH_PULSEAUDIO_DYNLOAD "Enable runtime dynamic PulseAudio libraries loading" OFF)
+else()
+ set(WITH_PULSEAUDIO OFF)
+endif()
+if(WIN32)
+ option(WITH_WASAPI "Enable Windows Audio Sessions API for audio support on Windows" ON)
+else()
+ set(WITH_WASAPI OFF)
+endif()
# Compression
option(WITH_LZO "Enable fast LZO compression (used for pointcache)" ON)
@@ -671,16 +689,11 @@ if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE)
)
endif()
-if(NOT WITH_AUDASPACE)
- if(WITH_OPENAL)
- message(WARNING "WITH_OPENAL requires WITH_AUDASPACE which is disabled")
- set(WITH_OPENAL OFF)
- endif()
- if(WITH_JACK)
- message(WARNING "WITH_JACK requires WITH_AUDASPACE which is disabled")
- set(WITH_JACK OFF)
- endif()
-endif()
+set_and_warn_dependency(WITH_AUDASPACE WITH_OPENAL OFF)
+set_and_warn_dependency(WITH_AUDASPACE WITH_COREAUDIO OFF)
+set_and_warn_dependency(WITH_AUDASPACE WITH_JACK OFF)
+set_and_warn_dependency(WITH_AUDASPACE WITH_PULSEAUDIO OFF)
+set_and_warn_dependency(WITH_AUDASPACE WITH_WASAPI OFF)
if(NOT WITH_SDL AND WITH_GHOST_SDL)
message(FATAL_ERROR "WITH_GHOST_SDL requires WITH_SDL")
@@ -1938,11 +1951,15 @@ if(FIRST_RUN)
info_cfg_option(WITH_CODEC_AVI)
info_cfg_option(WITH_CODEC_FFMPEG)
info_cfg_option(WITH_CODEC_SNDFILE)
+ info_cfg_option(WITH_COREAUDIO)
info_cfg_option(WITH_JACK)
info_cfg_option(WITH_JACK_DYNLOAD)
info_cfg_option(WITH_OPENAL)
info_cfg_option(WITH_SDL)
info_cfg_option(WITH_SDL_DYNLOAD)
+ info_cfg_option(WITH_PULSEAUDIO)
+ info_cfg_option(WITH_PULSEAUDIO_DYNLOAD)
+ info_cfg_option(WITH_WASAPI)
info_cfg_text("Compression:")
info_cfg_option(WITH_LZMA)
diff --git a/GNUmakefile b/GNUmakefile
index 41902809e30..3fe1850ca73 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -506,7 +506,7 @@ check_descriptions: .FORCE
#
source_archive: .FORCE
- ./build_files/utils/make_source_archive.sh
+ python3 ./build_files/utils/make_source_archive.py
INKSCAPE_BIN?="inkscape"
icons: .FORCE
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 09dcc91ce08..a3d694b4bc3 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -47,6 +47,7 @@ include(ExternalProject)
include(cmake/check_software.cmake)
include(cmake/options.cmake)
include(cmake/versions.cmake)
+include(cmake/download.cmake)
if(ENABLE_MINGW64)
include(cmake/setup_mingw64.cmake)
diff --git a/build_files/build_environment/cmake/alembic.cmake b/build_files/build_environment/cmake/alembic.cmake
index d865382eff3..9bc5a3778e2 100644
--- a/build_files/build_environment/cmake/alembic.cmake
+++ b/build_files/build_environment/cmake/alembic.cmake
@@ -44,9 +44,9 @@ set(ALEMBIC_EXTRA_ARGS
)
ExternalProject_Add(external_alembic
- URL ${ALEMBIC_URI}
+ URL file://${PACKAGE_DIR}/${ALEMBIC_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${ALEMBIC_MD5}
+ URL_HASH ${ALEMBIC_HASH_TYPE}=${ALEMBIC_HASH}
PREFIX ${BUILD_DIR}/alembic
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/alembic -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${ALEMBIC_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/alembic
diff --git a/build_files/build_environment/cmake/blosc.cmake b/build_files/build_environment/cmake/blosc.cmake
index 0a8e13746c8..89df67b7d58 100644
--- a/build_files/build_environment/cmake/blosc.cmake
+++ b/build_files/build_environment/cmake/blosc.cmake
@@ -36,9 +36,9 @@ set(BLOSC_EXTRA_ARGS ${BLOSC_EXTRA_ARGS}
)
ExternalProject_Add(external_blosc
- URL ${BLOSC_URI}
+ URL file://${PACKAGE_DIR}/${BLOSC_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${BLOSC_HASH}
+ URL_HASH ${BLOSC_HASH_TYPE}=${BLOSC_HASH}
PREFIX ${BUILD_DIR}/blosc
PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/blosc/src/external_blosc < ${PATCH_DIR}/blosc.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blosc ${DEFAULT_CMAKE_FLAGS} ${BLOSC_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake
index 3a90add9539..8b36af7dc41 100644
--- a/build_files/build_environment/cmake/boost.cmake
+++ b/build_files/build_environment/cmake/boost.cmake
@@ -86,9 +86,9 @@ set(BOOST_OPTIONS
string(TOLOWER ${BUILD_MODE} BOOST_BUILD_TYPE)
ExternalProject_Add(external_boost
- URL ${BOOST_URI}
+ URL file://${PACKAGE_DIR}/${BOOST_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${BOOST_HASH}
+ URL_HASH ${BOOST_HASH_TYPE}=${BOOST_HASH}
PREFIX ${BUILD_DIR}/boost
UPDATE_COMMAND ""
PATCH_COMMAND ${BOOST_PATCH_COMMAND}
diff --git a/build_files/build_environment/cmake/bzip2.cmake b/build_files/build_environment/cmake/bzip2.cmake
index bb2be7c634a..d60a50a148d 100644
--- a/build_files/build_environment/cmake/bzip2.cmake
+++ b/build_files/build_environment/cmake/bzip2.cmake
@@ -30,9 +30,9 @@ else()
endif()
ExternalProject_Add(external_bzip2
- URL ${BZIP2_URI}
+ URL file://${PACKAGE_DIR}/${BZIP2_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${BZIP2_HASH}
+ URL_HASH ${BZIP2_HASH_TYPE}=${BZIP2_HASH}
PREFIX ${BUILD_DIR}/bzip2
CONFIGURE_COMMAND echo .
BUILD_COMMAND ${BZIP2_CONFIGURE_ENV} && cd ${BUILD_DIR}/bzip2/src/external_bzip2/ && make CFLAGS=${BZIP2_CFLAGS} LDFLAGS=${BZIP2_LDFLAGS} -j${MAKE_THREADS}
diff --git a/build_files/build_environment/cmake/check_software.cmake b/build_files/build_environment/cmake/check_software.cmake
index b942e32c8b7..33c565832d9 100644
--- a/build_files/build_environment/cmake/check_software.cmake
+++ b/build_files/build_environment/cmake/check_software.cmake
@@ -72,9 +72,12 @@ if(UNIX)
"On Debian and Ubuntu:\n"
" apt install autoconf automake libtool yasm tcl ninja-build meson python3-mako\n"
"\n"
- "On macOS (with homebrew):\n"
+ "On macOS Intel (with homebrew):\n"
" brew install autoconf automake bison libtool pkg-config yasm\n"
"\n"
+ "On macOS ARM (with homebrew):\n"
+ " brew install autoconf automake bison flex libtool pkg-config yasm\n"
+ "\n"
"Other platforms:\n"
" Install equivalent packages.\n")
message(FATAL_ERROR "Install missing software before continuing")
diff --git a/build_files/build_environment/cmake/clew.cmake b/build_files/build_environment/cmake/clew.cmake
index ecc0f5ae4b6..57189844ae5 100644
--- a/build_files/build_environment/cmake/clew.cmake
+++ b/build_files/build_environment/cmake/clew.cmake
@@ -19,9 +19,9 @@
set(CLEW_EXTRA_ARGS)
ExternalProject_Add(external_clew
- URL ${CLEW_URI}
+ URL file://${PACKAGE_DIR}/${CLEW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${CLEW_HASH}
+ URL_HASH ${CLEW_HASH_TYPE}=${CLEW_HASH}
PREFIX ${BUILD_DIR}/clew
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/clew -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${CLEW_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/clew
diff --git a/build_files/build_environment/cmake/cuew.cmake b/build_files/build_environment/cmake/cuew.cmake
index bd0843b8940..39b3ac3b0cd 100644
--- a/build_files/build_environment/cmake/cuew.cmake
+++ b/build_files/build_environment/cmake/cuew.cmake
@@ -19,9 +19,9 @@
set(CUEW_EXTRA_ARGS)
ExternalProject_Add(external_cuew
- URL ${CUEW_URI}
+ URL file://${PACKAGE_DIR}/${CUEW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${CUEW_HASH}
+ URL_HASH ${CUEW_HASH_TYPE}=${CUEW_HASH}
PREFIX ${BUILD_DIR}/cuew
PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/cuew/src/external_cuew < ${PATCH_DIR}/cuew.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/cuew -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${CUEW_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
new file mode 100644
index 00000000000..f52957afeab
--- /dev/null
+++ b/build_files/build_environment/cmake/download.cmake
@@ -0,0 +1,93 @@
+function(download_source dep)
+ set(TARGET_FILE ${${dep}_FILE})
+ set(TARGET_HASH_TYPE ${${dep}_HASH_TYPE})
+ set(TARGET_HASH ${${dep}_HASH})
+ if(PACKAGE_USE_UPSTREAM_SOURCES)
+ set(TARGET_URI ${${dep}_URI})
+ else()
+ set(TARGET_URI https://svn.blender.org/svnroot/bf-blender/trunk/lib/packages/${TARGET_FILE})
+ endif()
+ set(TARGET_FILE ${PACKAGE_DIR}/${TARGET_FILE})
+ message("Checking source : ${dep} (${TARGET_FILE})")
+ if(NOT EXISTS ${TARGET_FILE})
+ message("Checking source : ${dep} - source not found downloading from ${TARGET_URI}")
+ file(DOWNLOAD ${TARGET_URI} ${TARGET_FILE}
+ TIMEOUT 60 # seconds
+ EXPECTED_HASH ${TARGET_HASH_TYPE}=${TARGET_HASH}
+ TLS_VERIFY ON
+ SHOW_PROGRESS
+ )
+ endif()
+endfunction(download_source)
+
+download_source(ZLIB)
+download_source(OPENAL)
+download_source(PNG)
+download_source(JPEG)
+download_source(BOOST)
+download_source(BLOSC)
+download_source(PTHREADS)
+download_source(OPENEXR)
+download_source(FREETYPE)
+download_source(GLEW)
+download_source(FREEGLUT)
+download_source(ALEMBIC)
+download_source(GLFW)
+download_source(CLEW)
+download_source(GLFW)
+download_source(CUEW)
+download_source(OPENSUBDIV)
+download_source(SDL)
+download_source(OPENCOLLADA)
+download_source(OPENCOLORIO)
+download_source(LLVM)
+download_source(OPENMP)
+download_source(OPENIMAGEIO)
+download_source(TIFF)
+download_source(OSL)
+download_source(PYTHON)
+download_source(TBB)
+download_source(OPENVDB)
+download_source(NANOVDB)
+download_source(NUMPY)
+download_source(LAME)
+download_source(OGG)
+download_source(VORBIS)
+download_source(THEORA)
+download_source(FLAC)
+download_source(VPX)
+download_source(OPUS)
+download_source(X264)
+download_source(XVIDCORE)
+download_source(OPENJPEG)
+download_source(FFMPEG)
+download_source(FFTW)
+download_source(ICONV)
+download_source(SNDFILE)
+if(WITH_WEBP)
+ download_source(WEBP)
+endif()
+download_source(SPNAV)
+download_source(JEMALLOC)
+download_source(XML2)
+download_source(TINYXML)
+download_source(YAMLCPP)
+download_source(EXPAT)
+download_source(PUGIXML)
+download_source(FLEXBISON)
+download_source(BZIP2)
+download_source(FFI)
+download_source(LZMA)
+download_source(SSL)
+download_source(SQLITE)
+download_source(EMBREE)
+download_source(USD)
+download_source(OIDN)
+download_source(LIBGLU)
+download_source(MESA)
+download_source(NASM)
+download_source(XR_OPENXR_SDK)
+download_source(ISPC)
+download_source(GMP)
+download_source(POTRACE)
+download_source(HARU)
diff --git a/build_files/build_environment/cmake/embree.cmake b/build_files/build_environment/cmake/embree.cmake
index 86b8256f98f..4830630def0 100644
--- a/build_files/build_environment/cmake/embree.cmake
+++ b/build_files/build_environment/cmake/embree.cmake
@@ -58,9 +58,9 @@ if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
)
else()
ExternalProject_Add(external_embree
- URL ${EMBREE_URI}
+ URL file://${PACKAGE_DIR}/${EMBREE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${EMBREE_HASH}
+ URL_HASH ${EMBREE_HASH_TYPE}=${EMBREE_HASH}
PREFIX ${BUILD_DIR}/embree
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/embree/src/external_embree < ${PATCH_DIR}/embree.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/embree ${DEFAULT_CMAKE_FLAGS} ${EMBREE_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/expat.cmake b/build_files/build_environment/cmake/expat.cmake
index 001f3941de1..13dd1a6b874 100644
--- a/build_files/build_environment/cmake/expat.cmake
+++ b/build_files/build_environment/cmake/expat.cmake
@@ -25,9 +25,9 @@ set(EXPAT_EXTRA_ARGS
)
ExternalProject_Add(external_expat
- URL ${EXPAT_URI}
+ URL file://${PACKAGE_DIR}/${EXPAT_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${EXPAT_HASH}
+ URL_HASH ${EXPAT_HASH_TYPE}=${EXPAT_HASH}
PREFIX ${BUILD_DIR}/expat
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/expat ${DEFAULT_CMAKE_FLAGS} ${EXPAT_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/expat
diff --git a/build_files/build_environment/cmake/ffi.cmake b/build_files/build_environment/cmake/ffi.cmake
index 73894f7478c..53d9e7be8ef 100644
--- a/build_files/build_environment/cmake/ffi.cmake
+++ b/build_files/build_environment/cmake/ffi.cmake
@@ -17,8 +17,8 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_ffi
- URL ${FFI_URI}
- URL_HASH SHA256=${FFI_HASH}
+ URL file://${PACKAGE_DIR}/${FFI_FILE}
+ URL_HASH ${FFI_HASH_TYPE}=${FFI_HASH}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
PREFIX ${BUILD_DIR}/ffi
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ffi/src/external_ffi/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/ffi
diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake
index ddfdbc86dac..2dad9c38877 100644
--- a/build_files/build_environment/cmake/ffmpeg.cmake
+++ b/build_files/build_environment/cmake/ffmpeg.cmake
@@ -60,9 +60,9 @@ elseif(UNIX)
endif()
ExternalProject_Add(external_ffmpeg
- URL ${FFMPEG_URI}
+ URL file://${PACKAGE_DIR}/${FFMPEG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${FFMPEG_HASH}
+ URL_HASH ${FFMPEG_HASH_TYPE}=${FFMPEG_HASH}
# OpenJpeg is compiled with pthread support on Linux, which is all fine and is what we
# want for maximum runtime performance, but due to static nature of that library we
# need to force ffmpeg to link against pthread, otherwise test program used by autoconf
diff --git a/build_files/build_environment/cmake/fftw.cmake b/build_files/build_environment/cmake/fftw.cmake
index b359df2f47d..fb2f0e1ea6a 100644
--- a/build_files/build_environment/cmake/fftw.cmake
+++ b/build_files/build_environment/cmake/fftw.cmake
@@ -28,9 +28,9 @@ else()
endif()
ExternalProject_Add(external_fftw3
- URL ${FFTW_URI}
+ URL file://${PACKAGE_DIR}/${FFTW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${FFTW_HASH}
+ URL_HASH ${FFTW_HASH_TYPE}=${FFTW_HASH}
PREFIX ${BUILD_DIR}/fftw3
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && ${CONFIGURE_COMMAND} ${FFTW_EXTRA_ARGS} --prefix=${mingw_LIBDIR}/fftw3
PATCH_COMMAND ${FFTW3_PATCH_COMMAND}
diff --git a/build_files/build_environment/cmake/flac.cmake b/build_files/build_environment/cmake/flac.cmake
index 2cc9a02fe3b..20c5b5d3544 100644
--- a/build_files/build_environment/cmake/flac.cmake
+++ b/build_files/build_environment/cmake/flac.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_flac
- URL ${FLAC_URI}
+ URL file://${PACKAGE_DIR}/${FLAC_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${FLAC_HASH}
+ URL_HASH ${FLAC_HASH_TYPE}=${FLAC_HASH}
PREFIX ${BUILD_DIR}/flac
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/flac --disable-shared --enable-static
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && make -j${MAKE_THREADS}
diff --git a/build_files/build_environment/cmake/flexbison.cmake b/build_files/build_environment/cmake/flexbison.cmake
index d4363eb07e1..1c8adfc313c 100644
--- a/build_files/build_environment/cmake/flexbison.cmake
+++ b/build_files/build_environment/cmake/flexbison.cmake
@@ -19,9 +19,9 @@
set(FLEXBISON_EXTRA_ARGS)
ExternalProject_Add(external_flexbison
- URL ${FLEXBISON_URI}
+ URL file://${PACKAGE_DIR}/${FLEXBISON_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${FLEXBISON_HASH}
+ URL_HASH ${FLEXBISON_HASH_TYPE}=${FLEXBISON_HASH}
PREFIX ${BUILD_DIR}/flexbison
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/flexbison ${DEFAULT_CMAKE_FLAGS} ${FLEXBISON_EXTRA_ARGS}
CONFIGURE_COMMAND echo .
diff --git a/build_files/build_environment/cmake/freeglut.cmake b/build_files/build_environment/cmake/freeglut.cmake
index 39b09f92630..ce51fac4724 100644
--- a/build_files/build_environment/cmake/freeglut.cmake
+++ b/build_files/build_environment/cmake/freeglut.cmake
@@ -24,9 +24,9 @@ if(WIN32)
)
ExternalProject_Add(external_freeglut
- URL ${FREEGLUT_URI}
+ URL file://${PACKAGE_DIR}/${FREEGLUT_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${FREEGLUT_HASH}
+ URL_HASH ${FREEGLUT_HASH_TYPE}=${FREEGLUT_HASH}
PREFIX ${BUILD_DIR}/freeglut
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/freeglut ${DEFAULT_C_FLAGS} ${DEFAULT_CXX_FLAGS} ${FREEGLUT_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/freeglut
diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake
index fefe2c900bc..49a83cb3377 100644
--- a/build_files/build_environment/cmake/freetype.cmake
+++ b/build_files/build_environment/cmake/freetype.cmake
@@ -28,9 +28,9 @@ set(FREETYPE_EXTRA_ARGS
-DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec=TRUE)
ExternalProject_Add(external_freetype
- URL ${FREETYPE_URI}
+ URL file://${PACKAGE_DIR}/${FREETYPE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${FREETYPE_HASH}
+ URL_HASH ${FREETYPE_HASH_TYPE}=${FREETYPE_HASH}
PREFIX ${BUILD_DIR}/freetype
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/freetype ${DEFAULT_CMAKE_FLAGS} ${FREETYPE_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/freetype
diff --git a/build_files/build_environment/cmake/glew.cmake b/build_files/build_environment/cmake/glew.cmake
index 2f8b88e8ddf..b37aaf77c78 100644
--- a/build_files/build_environment/cmake/glew.cmake
+++ b/build_files/build_environment/cmake/glew.cmake
@@ -22,9 +22,9 @@ set(GLEW_EXTRA_ARGS
)
ExternalProject_Add(external_glew
- URL ${GLEW_URI}
+ URL file://${PACKAGE_DIR}/${GLEW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${GLEW_HASH}
+ URL_HASH ${GLEW_HASH_TYPE}=${GLEW_HASH}
PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_glew.txt ${BUILD_DIR}/glew/src/external_glew/CMakeLists.txt
PREFIX ${BUILD_DIR}/glew
CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/glew ${DEFAULT_CMAKE_FLAGS} ${GLEW_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/glfw.cmake b/build_files/build_environment/cmake/glfw.cmake
index 3a61c195ad6..eefdfd49664 100644
--- a/build_files/build_environment/cmake/glfw.cmake
+++ b/build_files/build_environment/cmake/glfw.cmake
@@ -19,9 +19,9 @@
set(GLFW_EXTRA_ARGS)
ExternalProject_Add(external_glfw
- URL ${GLFW_URI}
+ URL file://${PACKAGE_DIR}/${GLFW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${GLFW_HASH}
+ URL_HASH ${GLFW_HASH_TYPE}=${GLFW_HASH}
PREFIX ${BUILD_DIR}/glfw
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/glfw -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${GLFW_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/glfw
diff --git a/build_files/build_environment/cmake/gmp.cmake b/build_files/build_environment/cmake/gmp.cmake
index 7e3bb3258a4..323630a63aa 100644
--- a/build_files/build_environment/cmake/gmp.cmake
+++ b/build_files/build_environment/cmake/gmp.cmake
@@ -46,9 +46,9 @@ elseif(UNIX)
endif()
ExternalProject_Add(external_gmp
- URL ${GMP_URI}
+ URL file://${PACKAGE_DIR}/${GMP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${GMP_HASH}
+ URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH}
PREFIX ${BUILD_DIR}/gmp
CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/gmp ${GMP_OPTIONS} ${GMP_EXTRA_ARGS}
BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make -j${MAKE_THREADS}
@@ -84,9 +84,9 @@ if(WIN32)
# given the C++ ABI between MSVC and mingw is not compatible, we need to build the bindings
# with MSVC, while GMP can only be build with mingw.
ExternalProject_Add(external_gmpxx
- URL ${GMP_URI}
+ URL file://${PACKAGE_DIR}/${GMP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${GMP_HASH}
+ URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH}
PREFIX ${BUILD_DIR}/gmpxx
PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_gmpxx.txt ${BUILD_DIR}/gmpxx/src/external_gmpxx/CMakeLists.txt &&
${CMAKE_COMMAND} -E copy ${PATCH_DIR}/config_gmpxx.h ${BUILD_DIR}/gmpxx/src/external_gmpxx/config.h
diff --git a/build_files/build_environment/cmake/haru.cmake b/build_files/build_environment/cmake/haru.cmake
index 7382095f459..4ea83857803 100644
--- a/build_files/build_environment/cmake/haru.cmake
+++ b/build_files/build_environment/cmake/haru.cmake
@@ -24,9 +24,9 @@ set(HARU_EXTRA_ARGS
)
ExternalProject_Add(external_haru
- URL ${HARU_URI}
+ URL file://${PACKAGE_DIR}/${HARU_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${HARU_HASH}
+ URL_HASH ${HARU_HASH_TYPE}=${HARU_HASH}
PREFIX ${BUILD_DIR}/haru
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/haru/src/external_haru < ${PATCH_DIR}/haru.diff
CMAKE_ARGS
diff --git a/build_files/build_environment/cmake/iconv.cmake b/build_files/build_environment/cmake/iconv.cmake
index 5be677392e6..bb9fe24e0fb 100644
--- a/build_files/build_environment/cmake/iconv.cmake
+++ b/build_files/build_environment/cmake/iconv.cmake
@@ -19,9 +19,9 @@
set(ICONV_EXTRA_ARGS)
ExternalProject_Add(external_iconv
- URL ${ICONV_URI}
+ URL file://${PACKAGE_DIR}/${ICONV_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${ICONV_HASH}
+ URL_HASH ${ICONV_HASH_TYPE}=${ICONV_HASH}
PREFIX ${BUILD_DIR}/iconv
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && ${CONFIGURE_COMMAND} --enable-static --prefix=${mingw_LIBDIR}/iconv
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && make -j${MAKE_THREADS}
diff --git a/build_files/build_environment/cmake/ispc.cmake b/build_files/build_environment/cmake/ispc.cmake
index dd6cf5a7d40..e8a4dedcdaa 100644
--- a/build_files/build_environment/cmake/ispc.cmake
+++ b/build_files/build_environment/cmake/ispc.cmake
@@ -63,9 +63,9 @@ set(ISPC_EXTRA_ARGS
)
ExternalProject_Add(external_ispc
- URL ${ISPC_URI}
+ URL file://${PACKAGE_DIR}/${ISPC_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${ISPC_HASH}
+ URL_HASH ${ISPC_HASH_TYPE}=${ISPC_HASH}
PREFIX ${BUILD_DIR}/ispc
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/ispc/src/external_ispc < ${PATCH_DIR}/ispc.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ispc -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${ISPC_EXTRA_ARGS} ${BUILD_DIR}/ispc/src/external_ispc
diff --git a/build_files/build_environment/cmake/jemalloc.cmake b/build_files/build_environment/cmake/jemalloc.cmake
index 30f584ac2ee..f156ae0fe40 100644
--- a/build_files/build_environment/cmake/jemalloc.cmake
+++ b/build_files/build_environment/cmake/jemalloc.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_jemalloc
- URL ${JEMALLOC_URI}
+ URL file://${PACKAGE_DIR}/${JEMALLOC_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${JEMALLOC_HASH}
+ URL_HASH ${JEMALLOC_HASH_TYPE}=${JEMALLOC_HASH}
PREFIX ${BUILD_DIR}/jemalloc
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/jemalloc --disable-shared --enable-static --with-pic
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && make -j${MAKE_THREADS}
diff --git a/build_files/build_environment/cmake/jpeg.cmake b/build_files/build_environment/cmake/jpeg.cmake
index 7b03a1b4f3c..d9eca5ed5cd 100644
--- a/build_files/build_environment/cmake/jpeg.cmake
+++ b/build_files/build_environment/cmake/jpeg.cmake
@@ -21,9 +21,9 @@ if(WIN32)
set(JPEG_EXTRA_ARGS -DNASM=${NASM_PATH} -DWITH_JPEG8=ON -DCMAKE_DEBUG_POSTFIX=d -DWITH_CRT_DLL=On)
ExternalProject_Add(external_jpeg
- URL ${JPEG_URI}
+ URL file://${PACKAGE_DIR}/${JPEG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${JPEG_HASH}
+ URL_HASH ${JPEG_HASH_TYPE}=${JPEG_HASH}
PREFIX ${BUILD_DIR}/jpg
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/jpg ${DEFAULT_CMAKE_FLAGS} ${JPEG_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/jpg
@@ -50,9 +50,9 @@ else(WIN32)
-DCMAKE_INSTALL_LIBDIR=${LIBDIR}/jpg/lib)
ExternalProject_Add(external_jpeg
- URL ${JPEG_URI}
+ URL file://${PACKAGE_DIR}/${JPEG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${JPEG_HASH}
+ URL_HASH ${JPEG_HASH_TYPE}=${JPEG_HASH}
PREFIX ${BUILD_DIR}/jpg
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/jpg ${DEFAULT_CMAKE_FLAGS} ${JPEG_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/jpg
diff --git a/build_files/build_environment/cmake/lame.cmake b/build_files/build_environment/cmake/lame.cmake
index d60784e8a40..c6570642c84 100644
--- a/build_files/build_environment/cmake/lame.cmake
+++ b/build_files/build_environment/cmake/lame.cmake
@@ -24,9 +24,9 @@ if(MSVC)
endif()
ExternalProject_Add(external_lame
- URL ${LAME_URI}
+ URL file://${PACKAGE_DIR}/${LAME_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${LAME_HASH}
+ URL_HASH ${LAME_HASH_TYPE}=${LAME_HASH}
PREFIX ${BUILD_DIR}/lame
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/lame --disable-shared --enable-static ${LAME_EXTRA_ARGS}
--enable-export=full
diff --git a/build_files/build_environment/cmake/libglu.cmake b/build_files/build_environment/cmake/libglu.cmake
index d1b7647eca3..da0a48f6264 100644
--- a/build_files/build_environment/cmake/libglu.cmake
+++ b/build_files/build_environment/cmake/libglu.cmake
@@ -27,9 +27,9 @@ set(LIBGLU_EXTRA_FLAGS
)
ExternalProject_Add(external_libglu
- URL ${LIBGLU_URI}
+ URL file://${PACKAGE_DIR}/${LIBGLU_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${LIBGLU_HASH}
+ URL_HASH ${LIBGLU_HASH_TYPE}=${LIBGLU_HASH}
PREFIX ${BUILD_DIR}/libglu
CONFIGURE_COMMAND ${CONFIGURE_ENV} &&
cd ${BUILD_DIR}/libglu/src/external_libglu/ &&
diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake
index da2f7364e4a..f067267a416 100644
--- a/build_files/build_environment/cmake/llvm.cmake
+++ b/build_files/build_environment/cmake/llvm.cmake
@@ -52,9 +52,9 @@ endif()
# short project name due to long filename issues on windows
ExternalProject_Add(ll
- URL ${LLVM_URI}
+ URL file://${PACKAGE_DIR}/${LLVM_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${LLVM_HASH}
+ URL_HASH ${LLVM_HASH_TYPE}=${LLVM_HASH}
CMAKE_GENERATOR ${LLVM_GENERATOR}
LIST_SEPARATOR ^^
PREFIX ${BUILD_DIR}/ll
diff --git a/build_files/build_environment/cmake/lzma.cmake b/build_files/build_environment/cmake/lzma.cmake
index ecceb1172b4..bd08e7be0e4 100644
--- a/build_files/build_environment/cmake/lzma.cmake
+++ b/build_files/build_environment/cmake/lzma.cmake
@@ -19,9 +19,9 @@
set(LZMA_PATCH_CMD echo .)
ExternalProject_Add(external_lzma
- URL ${LZMA_URI}
+ URL file://${PACKAGE_DIR}/${LZMA_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${LZMA_HASH}
+ URL_HASH ${LZMA_HASH_TYPE}=${LZMA_HASH}
PREFIX ${BUILD_DIR}/lzma
PATCH_COMMAND ${LZMA_PATCH_CMD}
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lzma/src/external_lzma/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/lzma
diff --git a/build_files/build_environment/cmake/mesa.cmake b/build_files/build_environment/cmake/mesa.cmake
index e9782a0976f..45cc244e813 100644
--- a/build_files/build_environment/cmake/mesa.cmake
+++ b/build_files/build_environment/cmake/mesa.cmake
@@ -53,9 +53,9 @@ set(MESA_EXTRA_FLAGS
)
ExternalProject_Add(external_mesa
- URL ${MESA_URI}
+ URL file://${PACKAGE_DIR}/${MESA_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${MESA_HASH}
+ URL_HASH ${MESA_HASH_TYPE}=${MESA_HASH}
PREFIX ${BUILD_DIR}/mesa
CONFIGURE_COMMAND ${CONFIGURE_ENV} &&
cd ${BUILD_DIR}/mesa/src/external_mesa/ &&
diff --git a/build_files/build_environment/cmake/nanovdb.cmake b/build_files/build_environment/cmake/nanovdb.cmake
index 89e7c38642d..0baaf80c254 100644
--- a/build_files/build_environment/cmake/nanovdb.cmake
+++ b/build_files/build_environment/cmake/nanovdb.cmake
@@ -37,9 +37,9 @@ set(NANOVDB_EXTRA_ARGS
)
ExternalProject_Add(nanovdb
- URL ${NANOVDB_URI}
+ URL file://${PACKAGE_DIR}/${NANOVDB_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${NANOVDB_HASH}
+ URL_HASH ${NANOVDB_HASH_TYPE}=${NANOVDB_HASH}
PREFIX ${BUILD_DIR}/nanovdb
SOURCE_SUBDIR nanovdb
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/nanovdb ${DEFAULT_CMAKE_FLAGS} ${NANOVDB_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/nasm.cmake b/build_files/build_environment/cmake/nasm.cmake
index 37a57273bfe..3187e2b8045 100644
--- a/build_files/build_environment/cmake/nasm.cmake
+++ b/build_files/build_environment/cmake/nasm.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_nasm
- URL ${NASM_URI}
+ URL file://${PACKAGE_DIR}/${NASM_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${NASM_HASH}
+ URL_HASH ${NASM_HASH_TYPE}=${NASM_HASH}
PREFIX ${BUILD_DIR}/nasm
PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/nasm/src/external_nasm < ${PATCH_DIR}/nasm.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && ./autogen.sh && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/nasm
diff --git a/build_files/build_environment/cmake/numpy.cmake b/build_files/build_environment/cmake/numpy.cmake
index 7a1b00895f4..73fa6e75556 100644
--- a/build_files/build_environment/cmake/numpy.cmake
+++ b/build_files/build_environment/cmake/numpy.cmake
@@ -32,9 +32,9 @@ endif()
set(NUMPY_POSTFIX)
ExternalProject_Add(external_numpy
- URL ${NUMPY_URI}
+ URL file://${PACKAGE_DIR}/${NUMPY_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${NUMPY_HASH}
+ URL_HASH ${NUMPY_HASH_TYPE}=${NUMPY_HASH}
PREFIX ${BUILD_DIR}/numpy
PATCH_COMMAND ${NUMPY_PATCH}
CONFIGURE_COMMAND ""
diff --git a/build_files/build_environment/cmake/ogg.cmake b/build_files/build_environment/cmake/ogg.cmake
index 808a35c6e4d..16257c6f039 100644
--- a/build_files/build_environment/cmake/ogg.cmake
+++ b/build_files/build_environment/cmake/ogg.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_ogg
- URL ${OGG_URI}
+ URL file://${PACKAGE_DIR}/${OGG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${OGG_HASH}
+ URL_HASH ${OGG_HASH_TYPE}=${OGG_HASH}
PREFIX ${BUILD_DIR}/ogg
PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/ogg/src/external_ogg < ${PATCH_DIR}/ogg.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/ogg --disable-shared --enable-static
diff --git a/build_files/build_environment/cmake/openal.cmake b/build_files/build_environment/cmake/openal.cmake
index 315f2e8ba7e..36165d9857c 100644
--- a/build_files/build_environment/cmake/openal.cmake
+++ b/build_files/build_environment/cmake/openal.cmake
@@ -46,9 +46,9 @@ if(BUILD_MODE STREQUAL Release)
endif()
ExternalProject_Add(external_openal
- URL ${OPENAL_URI}
+ URL file://${PACKAGE_DIR}/${OPENAL_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENAL_HASH}
+ URL_HASH ${OPENAL_HASH_TYPE}=${OPENAL_HASH}
PREFIX ${BUILD_DIR}/openal
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openal ${DEFAULT_CMAKE_FLAGS} ${OPENAL_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/openal
diff --git a/build_files/build_environment/cmake/opencollada.cmake b/build_files/build_environment/cmake/opencollada.cmake
index e1a8abc40ce..417c4d21594 100644
--- a/build_files/build_environment/cmake/opencollada.cmake
+++ b/build_files/build_environment/cmake/opencollada.cmake
@@ -23,9 +23,9 @@ if(UNIX)
endif()
ExternalProject_Add(external_opencollada
- URL ${OPENCOLLADA_URI}
+ URL file://${PACKAGE_DIR}/${OPENCOLLADA_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENCOLLADA_HASH}
+ URL_HASH ${OPENCOLLADA_HASH_TYPE}=${OPENCOLLADA_HASH}
PREFIX ${BUILD_DIR}/opencollada
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencollada/src/external_opencollada < ${PATCH_DIR}/opencollada.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencollada ${DEFAULT_CMAKE_FLAGS} ${OPENCOLLADA_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/opencolorio.cmake b/build_files/build_environment/cmake/opencolorio.cmake
index 87099a06d17..bd03be5ebff 100644
--- a/build_files/build_environment/cmake/opencolorio.cmake
+++ b/build_files/build_environment/cmake/opencolorio.cmake
@@ -55,9 +55,9 @@ else()
endif()
ExternalProject_Add(external_opencolorio
- URL ${OPENCOLORIO_URI}
+ URL file://${PACKAGE_DIR}/${OPENCOLORIO_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENCOLORIO_HASH}
+ URL_HASH ${OPENCOLORIO_HASH_TYPE}=${OPENCOLORIO_HASH}
PREFIX ${BUILD_DIR}/opencolorio
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencolorio/src/external_opencolorio < ${PATCH_DIR}/opencolorio.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencolorio ${DEFAULT_CMAKE_FLAGS} ${OPENCOLORIO_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/openexr.cmake b/build_files/build_environment/cmake/openexr.cmake
index 38dbeecc3eb..0ca7693aeb7 100644
--- a/build_files/build_environment/cmake/openexr.cmake
+++ b/build_files/build_environment/cmake/openexr.cmake
@@ -42,9 +42,9 @@ set(OPENEXR_EXTRA_ARGS
)
ExternalProject_Add(external_openexr
- URL ${OPENEXR_URI}
+ URL file://${PACKAGE_DIR}/${OPENEXR_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENEXR_HASH}
+ URL_HASH ${OPENEXR_HASH_TYPE}=${OPENEXR_HASH}
PREFIX ${BUILD_DIR}/openexr
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openexr ${DEFAULT_CMAKE_FLAGS} ${OPENEXR_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/openexr
diff --git a/build_files/build_environment/cmake/openimagedenoise.cmake b/build_files/build_environment/cmake/openimagedenoise.cmake
index 7947fc31470..f927d6c231c 100644
--- a/build_files/build_environment/cmake/openimagedenoise.cmake
+++ b/build_files/build_environment/cmake/openimagedenoise.cmake
@@ -41,9 +41,9 @@ else()
endif()
ExternalProject_Add(external_openimagedenoise
- URL ${OIDN_URI}
+ URL file://${PACKAGE_DIR}/${OIDN_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OIDN_HASH}
+ URL_HASH ${OIDN_HASH_TYPE}=${OIDN_HASH}
PREFIX ${BUILD_DIR}/openimagedenoise
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimagedenoise/src/external_openimagedenoise < ${PATCH_DIR}/oidn.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimagedenoise ${DEFAULT_CMAKE_FLAGS} ${OIDN_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/openimageio.cmake b/build_files/build_environment/cmake/openimageio.cmake
index 50fd67eca8e..68d9bd96db3 100644
--- a/build_files/build_environment/cmake/openimageio.cmake
+++ b/build_files/build_environment/cmake/openimageio.cmake
@@ -120,9 +120,9 @@ set(OPENIMAGEIO_EXTRA_ARGS
)
ExternalProject_Add(external_openimageio
- URL ${OPENIMAGEIO_URI}
+ URL file://${PACKAGE_DIR}/${OPENIMAGEIO_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENIMAGEIO_HASH}
+ URL_HASH ${OPENIMAGEIO_HASH_TYPE}=${OPENIMAGEIO_HASH}
PREFIX ${BUILD_DIR}/openimageio
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/openjpeg.cmake b/build_files/build_environment/cmake/openjpeg.cmake
index 9973a9d9cee..9396e05aff8 100644
--- a/build_files/build_environment/cmake/openjpeg.cmake
+++ b/build_files/build_environment/cmake/openjpeg.cmake
@@ -28,9 +28,9 @@ else()
endif()
ExternalProject_Add(external_openjpeg
- URL ${OPENJPEG_URI}
+ URL file://${PACKAGE_DIR}/${OPENJPEG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${OPENJPEG_HASH}
+ URL_HASH ${OPENJPEG_HASH_TYPE}=${OPENJPEG_HASH}
PREFIX ${BUILD_DIR}/openjpeg
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build && ${CMAKE_COMMAND} ${OPENJPEG_EXTRA_ARGS} -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openjpeg -DBUILD_SHARED_LIBS=Off -DBUILD_THIRDPARTY=OFF ${BUILD_DIR}/openjpeg/src/external_openjpeg
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build/ && make -j${MAKE_THREADS}
@@ -42,9 +42,9 @@ ExternalProject_Add(external_openjpeg
if(MSVC)
set(OPENJPEG_EXTRA_ARGS ${DEFAULT_CMAKE_FLAGS})
ExternalProject_Add(external_openjpeg_msvc
- URL ${OPENJPEG_URI}
+ URL file://${PACKAGE_DIR}/${OPENJPEG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${OPENJPEG_HASH}
+ URL_HASH ${OPENJPEG_HASH_TYPE}=${OPENJPEG_HASH}
PREFIX ${BUILD_DIR}/openjpeg_msvc
CMAKE_ARGS ${OPENJPEG_EXTRA_ARGS} -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openjpeg_msvc -DBUILD_SHARED_LIBS=Off -DBUILD_THIRDPARTY=OFF
INSTALL_DIR ${LIBDIR}/openjpeg_msvc
diff --git a/build_files/build_environment/cmake/openmp.cmake b/build_files/build_environment/cmake/openmp.cmake
index 92a96b4dd8b..96081c7fc49 100644
--- a/build_files/build_environment/cmake/openmp.cmake
+++ b/build_files/build_environment/cmake/openmp.cmake
@@ -18,9 +18,9 @@
ExternalProject_Add(external_openmp
- URL ${OPENMP_URI}
+ URL file://${PACKAGE_DIR}/${OPENMP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENMP_HASH}
+ URL_HASH ${OPENMP_HASH_TYPE}=${OPENMP_HASH}
PREFIX ${BUILD_DIR}/openmp
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openmp/src/external_openmp < ${PATCH_DIR}/openmp.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openmp ${DEFAULT_CMAKE_FLAGS}
diff --git a/build_files/build_environment/cmake/opensubdiv.cmake b/build_files/build_environment/cmake/opensubdiv.cmake
index d183b9f02b7..c5da9e94ba4 100644
--- a/build_files/build_environment/cmake/opensubdiv.cmake
+++ b/build_files/build_environment/cmake/opensubdiv.cmake
@@ -65,9 +65,9 @@ else()
endif()
ExternalProject_Add(external_opensubdiv
- URL ${OPENSUBDIV_URI}
+ URL file://${PACKAGE_DIR}/${OPENSUBDIV_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENSUBDIV_HASH}
+ URL_HASH ${OPENSUBDIV_HASH_TYPE}=${OPENSUBDIV_HASH}
PREFIX ${BUILD_DIR}/opensubdiv
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opensubdiv -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${OPENSUBDIV_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/opensubdiv
diff --git a/build_files/build_environment/cmake/openvdb.cmake b/build_files/build_environment/cmake/openvdb.cmake
index 704a8269c22..11415416d74 100644
--- a/build_files/build_environment/cmake/openvdb.cmake
+++ b/build_files/build_environment/cmake/openvdb.cmake
@@ -77,9 +77,9 @@ else()
endif()
ExternalProject_Add(openvdb
- URL ${OPENVDB_URI}
+ URL file://${PACKAGE_DIR}/${OPENVDB_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${OPENVDB_HASH}
+ URL_HASH ${OPENVDB_HASH_TYPE}=${OPENVDB_HASH}
PREFIX ${BUILD_DIR}/openvdb
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openvdb ${DEFAULT_CMAKE_FLAGS} ${OPENVDB_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake
index cfbe28b99c7..5091a5d9496 100644
--- a/build_files/build_environment/cmake/options.cmake
+++ b/build_files/build_environment/cmake/options.cmake
@@ -35,13 +35,25 @@ else(BUILD_MODE STREQUAL "Debug")
set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Release)
endif()
-option(DOWNLOAD_DIR "Path for downloaded files" ${CMAKE_CURRENT_SOURCE_DIR}/downloads)
+set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" CACHE STRING "Path for downloaded files")
+# look in blenders source folder for packages directory, if that exists
+# it will our package folder, otherwise it will be in the build folder
+if(EXISTS "${CMAKE_SOURCE_DIR}/../../packages")
+ set(PACKAGE_DIR_DEFAULT "${CMAKE_SOURCE_DIR}/../../packages")
+else()
+ set(PACKAGE_DIR_DEFAULT "${CMAKE_CURRENT_BINARY_DIR}/packages")
+endif()
+set(PACKAGE_DIR ${PACKAGE_DIR_DEFAULT} CACHE STRING "Path for downloaded source files")
+option(PACKAGE_USE_UPSTREAM_SOURCES "Use soures upstream to download the package sources, when OFF the blender mirror will be used" ON)
+
file(TO_CMAKE_PATH ${DOWNLOAD_DIR} DOWNLOAD_DIR)
+file(TO_CMAKE_PATH ${PACKAGE_DIR} PACKAGE_DIR)
set(PATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR}/patches)
set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/build)
message("LIBDIR = ${LIBDIR}")
message("DOWNLOAD_DIR = ${DOWNLOAD_DIR}")
+message("PACKAGE_DIR = ${PACKAGE_DIR}")
message("PATCH_DIR = ${PATCH_DIR}")
message("BUILD_DIR = ${BUILD_DIR}")
diff --git a/build_files/build_environment/cmake/opus.cmake b/build_files/build_environment/cmake/opus.cmake
index abaad94fa28..5037850aca3 100644
--- a/build_files/build_environment/cmake/opus.cmake
+++ b/build_files/build_environment/cmake/opus.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_opus
- URL ${OPUS_URI}
+ URL file://${PACKAGE_DIR}/${OPUS_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${OPUS_HASH}
+ URL_HASH ${OPUS_HASH_TYPE}=${OPUS_HASH}
PREFIX ${BUILD_DIR}/opus
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/opus
--disable-shared
diff --git a/build_files/build_environment/cmake/osl.cmake b/build_files/build_environment/cmake/osl.cmake
index 0628130134b..54e924b348a 100644
--- a/build_files/build_environment/cmake/osl.cmake
+++ b/build_files/build_environment/cmake/osl.cmake
@@ -77,10 +77,10 @@ if (APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
endif()
ExternalProject_Add(external_osl
- URL ${OSL_URI}
+ URL file://${PACKAGE_DIR}/${OSL_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
LIST_SEPARATOR ^^
- URL_HASH MD5=${OSL_HASH}
+ URL_HASH ${OSL_HASH_TYPE}=${OSL_HASH}
PREFIX ${BUILD_DIR}/osl
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/osl/src/external_osl < ${PATCH_DIR}/osl.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/osl -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${DEFAULT_CMAKE_FLAGS} ${OSL_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/png.cmake b/build_files/build_environment/cmake/png.cmake
index 9f8641873e6..d9248b61c98 100644
--- a/build_files/build_environment/cmake/png.cmake
+++ b/build_files/build_environment/cmake/png.cmake
@@ -27,9 +27,9 @@ if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
endif()
ExternalProject_Add(external_png
- URL ${PNG_URI}
+ URL file://${PACKAGE_DIR}/${PNG_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${PNG_HASH}
+ URL_HASH ${PNG_HASH_TYPE}=${PNG_HASH}
PREFIX ${BUILD_DIR}/png
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/png ${DEFAULT_CMAKE_FLAGS} ${PNG_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/png
diff --git a/build_files/build_environment/cmake/potrace.cmake b/build_files/build_environment/cmake/potrace.cmake
index 28e57c8c54a..999e093d811 100644
--- a/build_files/build_environment/cmake/potrace.cmake
+++ b/build_files/build_environment/cmake/potrace.cmake
@@ -21,9 +21,9 @@ set(POTRACE_EXTRA_ARGS
if((WIN32 AND BUILD_MODE STREQUAL Release) OR UNIX)
ExternalProject_Add(external_potrace
- URL ${POTRACE_URI}
+ URL file://${PACKAGE_DIR}/${POTRACE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${POTRACE_HASH}
+ URL_HASH ${POTRACE_HASH_TYPE}=${POTRACE_HASH}
PREFIX ${BUILD_DIR}/potrace
PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_potrace.txt ${BUILD_DIR}/potrace/src/external_potrace/CMakeLists.txt
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/potrace ${DEFAULT_CMAKE_FLAGS} ${POTRACE_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/pthreads.cmake b/build_files/build_environment/cmake/pthreads.cmake
index 7ddf6867e2b..9caae71daf1 100644
--- a/build_files/build_environment/cmake/pthreads.cmake
+++ b/build_files/build_environment/cmake/pthreads.cmake
@@ -27,9 +27,9 @@ if(WIN32)
set(PTHREADS_BUILD cd ${BUILD_DIR}/pthreads/src/external_pthreads/ && cd && nmake VC-static /e CPPFLAGS=${PTHREAD_CPPFLAGS})
ExternalProject_Add(external_pthreads
- URL ${PTHREADS_URI}
+ URL file://${PACKAGE_DIR}/${PTHREADS_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${PTHREADS_HASH}
+ URL_HASH ${PTHREADS_HASH_TYPE}=${PTHREADS_HASH}
PREFIX ${BUILD_DIR}/pthreads
CONFIGURE_COMMAND echo .
PATCH_COMMAND COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/pthreads/src/external_pthreads < ${PATCH_DIR}/pthreads.diff
diff --git a/build_files/build_environment/cmake/pugixml.cmake b/build_files/build_environment/cmake/pugixml.cmake
index 1f93723e936..41f15c5ef14 100644
--- a/build_files/build_environment/cmake/pugixml.cmake
+++ b/build_files/build_environment/cmake/pugixml.cmake
@@ -20,9 +20,9 @@ set(PUGIXML_EXTRA_ARGS
)
ExternalProject_Add(external_pugixml
- URL ${PUGIXML_URI}
+ URL file://${PACKAGE_DIR}/${PUGIXML_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${PUGIXML_HASH}
+ URL_HASH ${PUGIXML_HASH_TYPE}=${PUGIXML_HASH}
PREFIX ${BUILD_DIR}/pugixml
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/pugixml ${DEFAULT_CMAKE_FLAGS} ${PUGIXML_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/pugixml
diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake
index 7e718d22805..943db878c90 100644
--- a/build_files/build_environment/cmake/python.cmake
+++ b/build_files/build_environment/cmake/python.cmake
@@ -37,9 +37,9 @@ if(WIN32)
cmake_to_dos_path(${DOWNLOADS_EXTERNALS_FOLDER} DOWNLOADS_EXTERNALS_FOLDER_DOS)
ExternalProject_Add(external_python
- URL ${PYTHON_URI}
+ URL file://${PACKAGE_DIR}/${PYTHON_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${PYTHON_HASH}
+ URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH}
PREFIX ${BUILD_DIR}/python
CONFIGURE_COMMAND ""
BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p x64 -c ${BUILD_MODE}
@@ -90,9 +90,9 @@ else()
export PKG_CONFIG_PATH=${LIBDIR}/ffi/lib/pkgconfig)
ExternalProject_Add(external_python
- URL ${PYTHON_URI}
+ URL file://${PACKAGE_DIR}/${PYTHON_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${PYTHON_HASH}
+ URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH}
PREFIX ${BUILD_DIR}/python
PATCH_COMMAND ${PYTHON_PATCH}
CONFIGURE_COMMAND ${PYTHON_CONFIGURE_ENV} && ${PYTHON_CONFIGURE_EXTRA_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/python ${PYTHON_CONFIGURE_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/sdl.cmake b/build_files/build_environment/cmake/sdl.cmake
index 5dfe78601ff..c5594988234 100644
--- a/build_files/build_environment/cmake/sdl.cmake
+++ b/build_files/build_environment/cmake/sdl.cmake
@@ -30,9 +30,9 @@ else()
endif()
ExternalProject_Add(external_sdl
- URL ${SDL_URI}
+ URL file://${PACKAGE_DIR}/${SDL_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${SDL_HASH}
+ URL_HASH ${SDL_HASH_TYPE}=${SDL_HASH}
PREFIX ${BUILD_DIR}/sdl
PATCH_COMMAND ${PATCH_CMD} -p 0 -N -d ${BUILD_DIR}/sdl/src/external_sdl < ${PATCH_DIR}/sdl.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/sdl ${DEFAULT_CMAKE_FLAGS} ${SDL_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake
index df9b14c8887..37cee404561 100644
--- a/build_files/build_environment/cmake/sndfile.cmake
+++ b/build_files/build_environment/cmake/sndfile.cmake
@@ -34,9 +34,9 @@ else()
endif()
ExternalProject_Add(external_sndfile
- URL ${SNDFILE_URI}
+ URL file://${PACKAGE_DIR}/${SNDFILE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${SNDFILE_HASH}
+ URL_HASH ${SNDFILE_HASH_TYPE}=${SNDFILE_HASH}
PREFIX ${BUILD_DIR}/sndfile
PATCH_COMMAND ${SNDFILE_PATCH_CMD}
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && ${SNDFILE_ENV} ${CONFIGURE_COMMAND} ${SNDFILE_OPTIONS} --prefix=${mingw_LIBDIR}/sndfile
diff --git a/build_files/build_environment/cmake/spnav.cmake b/build_files/build_environment/cmake/spnav.cmake
index 5e67dbc5746..3a0cacc3d86 100644
--- a/build_files/build_environment/cmake/spnav.cmake
+++ b/build_files/build_environment/cmake/spnav.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_spnav
- URL ${SPNAV_URI}
+ URL file://${PACKAGE_DIR}/${SPNAV_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${SPNAV_HASH}
+ URL_HASH ${SPNAV_HASH_TYPE}=${SPNAV_HASH}
PREFIX ${BUILD_DIR}/spnav
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/spnav --disable-shared --enable-static --with-pic
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && make -j${MAKE_THREADS}
diff --git a/build_files/build_environment/cmake/sqlite.cmake b/build_files/build_environment/cmake/sqlite.cmake
index a77d3830b45..16fee8264de 100644
--- a/build_files/build_environment/cmake/sqlite.cmake
+++ b/build_files/build_environment/cmake/sqlite.cmake
@@ -60,9 +60,9 @@ if(UNIX)
endif()
ExternalProject_Add(external_sqlite
- URL ${SQLITE_URI}
+ URL file://${PACKAGE_DIR}/${SQLITE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA1=${SQLITE_HASH}
+ URL_HASH ${SQLITE_HASH_TYPE}=${SQLITE_HASH}
PREFIX ${BUILD_DIR}/sqlite
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/sqlite/src/external_sqlite < ${PATCH_DIR}/sqlite.diff
CONFIGURE_COMMAND ${SQLITE_CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/sqlite ${SQLITE_CONFIGURATION_ARGS}
diff --git a/build_files/build_environment/cmake/ssl.cmake b/build_files/build_environment/cmake/ssl.cmake
index e6741ebb385..4426cc876c6 100644
--- a/build_files/build_environment/cmake/ssl.cmake
+++ b/build_files/build_environment/cmake/ssl.cmake
@@ -31,9 +31,9 @@ else()
endif()
ExternalProject_Add(external_ssl
- URL ${SSL_URI}
+ URL file://${PACKAGE_DIR}/${SSL_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${SSL_HASH}
+ URL_HASH ${SSL_HASH_TYPE}=${SSL_HASH}
PREFIX ${BUILD_DIR}/ssl
PATCH_COMMAND ${SSL_PATCH_CMD}
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ssl/src/external_ssl/ && ${SSL_CONFIGURE_COMMAND} --prefix=${LIBDIR}/ssl
diff --git a/build_files/build_environment/cmake/tbb.cmake b/build_files/build_environment/cmake/tbb.cmake
index 99614f18d83..b006898e6fd 100644
--- a/build_files/build_environment/cmake/tbb.cmake
+++ b/build_files/build_environment/cmake/tbb.cmake
@@ -37,9 +37,9 @@ endif()
# CMake script for TBB from https://github.com/wjakob/tbb/blob/master/CMakeLists.txt
ExternalProject_Add(external_tbb
- URL ${TBB_URI}
+ URL file://${PACKAGE_DIR}/${TBB_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${TBB_HASH}
+ URL_HASH ${TBB_HASH_TYPE}=${TBB_HASH}
PREFIX ${BUILD_DIR}/tbb
PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_tbb.txt ${BUILD_DIR}/tbb/src/external_tbb/CMakeLists.txt &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2013/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/src/tbb/version_string.ver &&
diff --git a/build_files/build_environment/cmake/theora.cmake b/build_files/build_environment/cmake/theora.cmake
index b6f9c589423..fc69fed918d 100644
--- a/build_files/build_environment/cmake/theora.cmake
+++ b/build_files/build_environment/cmake/theora.cmake
@@ -23,9 +23,9 @@ else()
endif()
ExternalProject_Add(external_theora
- URL ${THEORA_URI}
+ URL file://${PACKAGE_DIR}/${THEORA_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${THEORA_HASH}
+ URL_HASH ${THEORA_HASH_TYPE}=${THEORA_HASH}
PREFIX ${BUILD_DIR}/theora
PATCH_COMMAND ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/theora/src/external_theora < ${PATCH_DIR}/theora.diff
CONFIGURE_COMMAND ${THEORA_CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/theora
diff --git a/build_files/build_environment/cmake/tiff.cmake b/build_files/build_environment/cmake/tiff.cmake
index fe2c82a6eaa..85f6643c4ef 100644
--- a/build_files/build_environment/cmake/tiff.cmake
+++ b/build_files/build_environment/cmake/tiff.cmake
@@ -34,9 +34,9 @@ set(TIFF_EXTRA_ARGS
)
ExternalProject_Add(external_tiff
- URL ${TIFF_URI}
+ URL file://${PACKAGE_DIR}/${TIFF_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${TIFF_HASH}
+ URL_HASH ${TIFF_HASH_TYPE}=${TIFF_HASH}
PREFIX ${BUILD_DIR}/tiff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tiff ${DEFAULT_CMAKE_FLAGS} ${TIFF_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/tiff
diff --git a/build_files/build_environment/cmake/usd.cmake b/build_files/build_environment/cmake/usd.cmake
index 5fa1872cabc..913cbdec3d3 100644
--- a/build_files/build_environment/cmake/usd.cmake
+++ b/build_files/build_environment/cmake/usd.cmake
@@ -53,9 +53,9 @@ set(USD_EXTRA_ARGS
)
ExternalProject_Add(external_usd
- URL ${USD_URI}
+ URL file://${PACKAGE_DIR}/${USD_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${USD_HASH}
+ URL_HASH ${USD_HASH_TYPE}=${USD_HASH}
PREFIX ${BUILD_DIR}/usd
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/usd -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${USD_EXTRA_ARGS}
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 96cffe6f3c2..97da5d54d48 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -19,37 +19,54 @@
set(ZLIB_VERSION 1.2.11)
set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz)
set(ZLIB_HASH 1c9f62f0778697a09d36121ead88e08e)
+set(ZLIB_HASH_TYPE MD5)
+set(ZLIB_FILE zlib-${ZLIB_VERSION}.tar.gz)
set(OPENAL_VERSION 1.20.1)
set(OPENAL_URI http://openal-soft.org/openal-releases/openal-soft-${OPENAL_VERSION}.tar.bz2)
set(OPENAL_HASH 556695068ce8375b89986083d810fd35)
+set(OPENAL_HASH_TYPE MD5)
+set(OPENAL_FILE openal-soft-${OPENAL_VERSION}.tar.bz2)
set(PNG_VERSION 1.6.37)
set(PNG_URI http://prdownloads.sourceforge.net/libpng/libpng-${PNG_VERSION}.tar.xz)
set(PNG_HASH 505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca)
+set(PNG_HASH_TYPE SHA256)
+set(PNG_FILE libpng-${PNG_VERSION}.tar.xz)
set(JPEG_VERSION 2.0.4)
set(JPEG_URI https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_VERSION}.tar.gz)
set(JPEG_HASH 44c43e4a9fb352f47090804529317c88)
+set(JPEG_HASH_TYPE MD5)
+set(JPEG_FILE libjpeg-turbo-${JPEG_VERSION}.tar.gz)
set(BOOST_VERSION 1.73.0)
set(BOOST_VERSION_NODOTS 1_73_0)
set(BOOST_VERSION_NODOTS_SHORT 1_73)
set(BOOST_URI https://dl.bintray.com/boostorg/release/${BOOST_VERSION}/source/boost_${BOOST_VERSION_NODOTS}.tar.gz)
set(BOOST_HASH 4036cd27ef7548b8d29c30ea10956196)
+set(BOOST_HASH_TYPE MD5)
+set(BOOST_FILE boost_${BOOST_VERSION_NODOTS}.tar.gz)
# Using old version as recommended by OpenVDB build documentation.
set(BLOSC_VERSION 1.5.0)
set(BLOSC_URI https://github.com/Blosc/c-blosc/archive/v${BLOSC_VERSION}.tar.gz)
set(BLOSC_HASH 6e4a49c8c06f05aa543f3312cfce3d55)
+set(BLOSC_HASH_TYPE MD5)
+set(BLOSC_FILE blosc-${BLOSC_VERSION}.tar.gz)
set(PTHREADS_VERSION 3.0.0)
-set(PTHREADS_URI http://sourceforge.mirrorservice.org/p/pt/pthreads4w/pthreads4w-code-v${PTHREADS_VERSION}.zip)
+set(PTHREADS_URI http://prdownloads.sourceforge.net/pthreads4w/pthreads4w-code-v${PTHREADS_VERSION}.zip)
set(PTHREADS_HASH f3bf81bb395840b3446197bcf4ecd653)
+set(PTHREADS_HASH_TYPE MD5)
+set(PTHREADS_FILE pthreads4w-code-${PTHREADS_VERSION}.zip)
set(OPENEXR_VERSION 2.5.5)
set(OPENEXR_URI https://github.com/AcademySoftwareFoundation/openexr/archive/v${OPENEXR_VERSION}.tar.gz)
set(OPENEXR_HASH 85e8a979092c9055d10ed103062d31a0)
+set(OPENEXR_HASH_TYPE MD5)
+set(OPENEXR_FILE openexr-${OPENEXR_VERSION}.tar.gz)
+
if(WIN32)
# Openexr started appending _d on its own so now
# we need to tell the build the postfix is _s while
@@ -69,97 +86,141 @@ endif()
set(FREETYPE_VERSION 2.10.2)
set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz)
set(FREETYPE_HASH b1cb620e4c875cd4d1bfa04945400945)
+set(FREETYPE_HASH_TYPE MD5)
+set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz)
set(GLEW_VERSION 1.13.0)
set(GLEW_URI http://prdownloads.sourceforge.net/glew/glew/${GLEW_VERSION}/glew-${GLEW_VERSION}.tgz)
set(GLEW_HASH 7cbada3166d2aadfc4169c4283701066)
+set(GLEW_HASH_TYPE MD5)
+set(GLEW_FILE glew-${GLEW_VERSION}.tgz)
set(FREEGLUT_VERSION 3.0.0)
-set(FREEGLUT_URI http://pilotfiber.dl.sourceforge.net/project/freeglut/freeglut/${FREEGLUT_VERSION}/freeglut-${FREEGLUT_VERSION}.tar.gz)
+set(FREEGLUT_URI http://prdownloads.sourceforge.net/freeglut/freeglut/${FREEGLUT_VERSION}/freeglut-${FREEGLUT_VERSION}.tar.gz)
set(FREEGLUT_HASH 90c3ca4dd9d51cf32276bc5344ec9754)
+set(FREEGLUT_HASH_TYPE MD5)
+set(FREEGLUT_FILE freeglut-${FREEGLUT_VERSION}.tar.gz)
set(ALEMBIC_VERSION 1.7.16)
set(ALEMBIC_URI https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.tar.gz)
-set(ALEMBIC_MD5 effcc86e42fe6605588e3de57bde6677)
+set(ALEMBIC_HASH effcc86e42fe6605588e3de57bde6677)
+set(ALEMBIC_HASH_TYPE MD5)
+set(ALEMBIC_FILE alembic-${ALEMBIC_VERSION}.tar.gz)
# hash is for 3.1.2
set(GLFW_GIT_UID 30306e54705c3adae9fe082c816a3be71963485c)
set(GLFW_URI https://github.com/glfw/glfw/archive/${GLFW_GIT_UID}.zip)
set(GLFW_HASH 20cacb1613da7eeb092f3ac4f6b2b3d0)
+set(GLFW_HASH_TYPE MD5)
+set(GLFW_FILE glfw-${GLFW_GIT_UID}.zip)
# latest uid in git as of 2016-04-01
set(CLEW_GIT_UID 277db43f6cafe8b27c6f1055f69dc67da4aeb299)
set(CLEW_URI https://github.com/OpenCLWrangler/clew/archive/${CLEW_GIT_UID}.zip)
set(CLEW_HASH 2c699d10ed78362e71f56fae2a4c5f98)
+set(CLEW_HASH_TYPE MD5)
+set(CLEW_FILE clew-${CLEW_GIT_UID}.zip)
# latest uid in git as of 2016-04-01
set(CUEW_GIT_UID 1744972026de9cf27c8a7dc39cf39cd83d5f922f)
set(CUEW_URI https://github.com/CudaWrangler/cuew/archive/${CUEW_GIT_UID}.zip)
set(CUEW_HASH 86760d62978ebfd96cd93f5aa1abaf4a)
+set(CUEW_HASH_TYPE MD5)
+set(CUEW_FILE cuew-${CUEW_GIT_UID}.zip)
set(OPENSUBDIV_VERSION v3_4_3)
set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz)
set(OPENSUBDIV_HASH 7bbfa275d021fb829e521df749160edb)
+set(OPENSUBDIV_HASH_TYPE MD5)
+set(OPENSUBDIV_FILE opensubdiv-${OPENSUBDIV_VERSION}.tar.gz)
set(SDL_VERSION 2.0.12)
set(SDL_URI https://www.libsdl.org/release/SDL2-${SDL_VERSION}.tar.gz)
set(SDL_HASH 783b6f2df8ff02b19bb5ce492b99c8ff)
+set(SDL_HASH_TYPE MD5)
+set(SDL_FILE SDL2-${SDL_VERSION}.tar.gz)
set(OPENCOLLADA_VERSION v1.6.68)
set(OPENCOLLADA_URI https://github.com/KhronosGroup/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz)
set(OPENCOLLADA_HASH ee7dae874019fea7be11613d07567493)
+set(OPENCOLLADA_HASH_TYPE MD5)
+set(OPENCOLLADA_FILE opencollada-${OPENCOLLADA_VERSION}.tar.gz)
set(OPENCOLORIO_VERSION 2.0.0)
set(OPENCOLORIO_URI https://github.com/AcademySoftwareFoundation/OpenColorIO/archive/v${OPENCOLORIO_VERSION}.tar.gz)
set(OPENCOLORIO_HASH 1a2e3478b6cd9a1549f24e1b2205e3f0)
+set(OPENCOLORIO_HASH_TYPE MD5)
+set(OPENCOLORIO_FILE OpenColorIO-${OPENCOLORIO_VERSION}.tar.gz)
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
# Newer version required by ISPC with arm support.
set(LLVM_VERSION 11.0.1)
set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz)
set(LLVM_HASH e700af40ab83463e4e9ab0ba3708312e)
+ set(LLVM_HASH_TYPE MD5)
+ set(LLVM_FILE llvm-project-${LLVM_VERSION}.src.tar.xz)
set(OPENMP_VERSION 9.0.1)
set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${OPENMP_VERSION}/openmp-${OPENMP_VERSION}.src.tar.xz)
set(OPENMP_HASH 6eade16057edbdecb3c4eef9daa2bfcf)
+ set(OPENMP_HASH_TYPE MD5)
+ set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz)
else()
set(LLVM_VERSION 9.0.1)
set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.tar.xz)
set(LLVM_HASH b4268e733dfe352960140dc07ef2efcb)
+ set(LLVM_HASH_TYPE MD5)
+ set(LLVM_FILE llvm-project-${LLVM_VERSION}.tar.xz)
set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/openmp-${LLVM_VERSION}.src.tar.xz)
set(OPENMP_HASH 6eade16057edbdecb3c4eef9daa2bfcf)
+ set(OPENMP_HASH_TYPE MD5)
+ set(OPENMP_FILE openmp-${LLVM_VERSION}.src.tar.xz)
endif()
set(OPENIMAGEIO_VERSION 2.1.15.0)
set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/Release-${OPENIMAGEIO_VERSION}.tar.gz)
set(OPENIMAGEIO_HASH f03aa5e3ac4795af04771ee4146e9832)
+set(OPENIMAGEIO_HASH_TYPE MD5)
+set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz)
set(TIFF_VERSION 4.1.0)
set(TIFF_URI http://download.osgeo.org/libtiff/tiff-${TIFF_VERSION}.tar.gz)
set(TIFF_HASH 2165e7aba557463acc0664e71a3ed424)
+set(TIFF_HASH_TYPE MD5)
+set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz)
set(OSL_VERSION 1.11.10.0)
set(OSL_URI https://github.com/imageworks/OpenShadingLanguage/archive/Release-${OSL_VERSION}.tar.gz)
set(OSL_HASH dfdc23597aeef083832cbada62211756)
+set(OSL_HASH_TYPE MD5)
+set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
set(PYTHON_VERSION 3.9.2)
set(PYTHON_SHORT_VERSION 3.9)
set(PYTHON_SHORT_VERSION_NO_DOTS 39)
set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz)
set(PYTHON_HASH f0dc9000312abeb16de4eccce9a870ab)
+set(PYTHON_HASH_TYPE MD5)
+set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz)
set(TBB_VERSION 2020_U2)
set(TBB_URI https://github.com/oneapi-src/oneTBB/archive/${TBB_VERSION}.tar.gz)
set(TBB_HASH 1b711ae956524855088df3bbf5ec65dc)
+set(TBB_HASH_TYPE MD5)
+set(TBB_FILE oneTBB-${TBB_VERSION}.tar.gz)
set(OPENVDB_VERSION 8.0.1)
set(OPENVDB_URI https://github.com/AcademySoftwareFoundation/openvdb/archive/v${OPENVDB_VERSION}.tar.gz)
set(OPENVDB_HASH 01b490be16cc0e15c690f9a153c21461)
+set(OPENVDB_HASH_TYPE MD5)
+set(OPENVDB_FILE openvdb-${OPENVDB_VERSION}.tar.gz)
set(NANOVDB_GIT_UID e62f7a0bf1e27397223c61ddeaaf57edf111b77f)
set(NANOVDB_URI https://github.com/AcademySoftwareFoundation/openvdb/archive/${NANOVDB_GIT_UID}.tar.gz)
set(NANOVDB_HASH 90919510bc6ccd630fedc56f748cb199)
+set(NANOVDB_HASH_TYPE MD5)
+set(NANOVDB_FILE nano-vdb-${NANOVDB_GIT_UID}.tar.gz)
set(IDNA_VERSION 2.10)
set(CHARDET_VERSION 4.0.0)
@@ -172,107 +233,148 @@ set(NUMPY_VERSION 1.19.5)
set(NUMPY_SHORT_VERSION 1.19)
set(NUMPY_URI https://github.com/numpy/numpy/releases/download/v${NUMPY_VERSION}/numpy-${NUMPY_VERSION}.zip)
set(NUMPY_HASH f6a1b48717c552bbc18f1adc3cc1fe0e)
+set(NUMPY_HASH_TYPE MD5)
+set(NUMPY_FILE numpy-${NUMPY_VERSION}.zip)
set(LAME_VERSION 3.100)
set(LAME_URI http://downloads.sourceforge.net/project/lame/lame/3.100/lame-${LAME_VERSION}.tar.gz)
set(LAME_HASH 83e260acbe4389b54fe08e0bdbf7cddb)
+set(LAME_HASH_TYPE MD5)
+set(LAME_FILE lame-${LAME_VERSION}.tar.gz)
set(OGG_VERSION 1.3.4)
set(OGG_URI http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz)
set(OGG_HASH fe5670640bd49e828d64d2879c31cb4dde9758681bb664f9bdbf159a01b0c76e)
+set(OGG_HASH_TYPE SHA256)
+set(OGG_FILE libogg-${OGG_VERSION}.tar.gz)
set(VORBIS_VERSION 1.3.6)
set(VORBIS_URI http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERSION}.tar.gz)
set(VORBIS_HASH 6ed40e0241089a42c48604dc00e362beee00036af2d8b3f46338031c9e0351cb)
+set(VORBIS_HASH_TYPE SHA256)
+set(VORBIS_FILE libvorbis-${VORBIS_VERSION}.tar.gz)
set(THEORA_VERSION 1.1.1)
set(THEORA_URI http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.bz2)
set(THEORA_HASH b6ae1ee2fa3d42ac489287d3ec34c5885730b1296f0801ae577a35193d3affbc)
+set(THEORA_HASH_TYPE SHA256)
+set(THEORA_FILE libtheora-${THEORA_VERSION}.tar.bz2)
set(FLAC_VERSION 1.3.3)
set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz)
set(FLAC_HASH 213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748)
+set(FLAC_HASH_TYPE SHA256)
+set(FLAC_FILE flac-${FLAC_VERSION}.tar.xz)
set(VPX_VERSION 1.8.2)
set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz)
set(VPX_HASH 8735d9fcd1a781ae6917f28f239a8aa358ce4864ba113ea18af4bb2dc8b474ac)
+set(VPX_HASH_TYPE SHA256)
+set(VPX_FILE libvpx-v${VPX_VERSION}.tar.gz)
set(OPUS_VERSION 1.3.1)
set(OPUS_URI https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz)
set(OPUS_HASH 65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d)
+set(OPUS_HASH_TYPE SHA256)
+set(OPUS_FILE opus-${OPUS_VERSION}.tar.gz)
-set(X264_URI https://code.videolan.org/videolan/x264/-/archive/33f9e1474613f59392be5ab6a7e7abf60fa63622/x264-33f9e1474613f59392be5ab6a7e7abf60fa63622.tar.gz)
+set(X264_VERSION 33f9e1474613f59392be5ab6a7e7abf60fa63622)
+set(X264_URI https://code.videolan.org/videolan/x264/-/archive/${X264_VERSION}/x264-${X264_VERSION}.tar.gz)
set(X264_HASH 5456450ee1ae02cd2328be3157367a232a0ab73315e8c8f80dab80469524f525)
+set(X264_HASH_TYPE SHA256)
+set(X264_FILE x264-${X264_VERSION}.tar.gz)
set(XVIDCORE_VERSION 1.3.7)
set(XVIDCORE_URI https://downloads.xvid.com/downloads/xvidcore-${XVIDCORE_VERSION}.tar.gz)
set(XVIDCORE_HASH abbdcbd39555691dd1c9b4d08f0a031376a3b211652c0d8b3b8aa9be1303ce2d)
+set(XVIDCORE_HASH_TYPE SHA256)
+set(XVIDCORE_FILE xvidcore-${XVIDCORE_VERSION}.tar.gz)
set(OPENJPEG_VERSION 2.3.1)
set(OPENJPEG_SHORT_VERSION 2.3)
set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz)
set(OPENJPEG_HASH 63f5a4713ecafc86de51bfad89cc07bb788e9bba24ebbf0c4ca637621aadb6a9)
+set(OPENJPEG_HASH_TYPE SHA256)
+set(OPENJPEG_FILE openjpeg-v${OPENJPEG_VERSION}.tar.gz)
set(FFMPEG_VERSION 4.2.3)
set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2)
set(FFMPEG_HASH 695fad11f3baf27784e24cb0e977b65a)
+set(FFMPEG_HASH_TYPE MD5)
+set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2)
set(FFTW_VERSION 3.3.8)
set(FFTW_URI http://www.fftw.org/fftw-${FFTW_VERSION}.tar.gz)
set(FFTW_HASH 8aac833c943d8e90d51b697b27d4384d)
+set(FFTW_HASH_TYPE MD5)
+set(FFTW_FILE fftw-${FFTW_VERSION}.tar.gz)
set(ICONV_VERSION 1.16)
set(ICONV_URI http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz)
set(ICONV_HASH 7d2a800b952942bb2880efb00cfd524c)
+set(ICONV_HASH_TYPE MD5)
+set(ICONV_FILE libiconv-${ICONV_VERSION}.tar.gz)
set(SNDFILE_VERSION 1.0.28)
set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_VERSION}.tar.gz)
set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c)
-
-# set(HIDAPI_VERSION 0.8.0-rc1)
-# set(HIDAPI_URI https://github.com/signal11/hidapi/archive/hidapi-${HIDAPI_VERSION}.tar.gz)
-# set(HIDAPI_HASH 069f9dd746edc37b6b6d0e3656f47199)
-
-set(HIDAPI_UID 89a6c75dc6f45ecabd4ddfbd2bf5ba6ad8ba38b5)
-set(HIDAPI_URI https://github.com/TheOnlyJoey/hidapi/archive/${HIDAPI_UID}.zip)
-set(HIDAPI_HASH b6e22f6b514f8bcf594989f20ffc46fb)
+set(SNDFILE_HASH_TYPE MD5)
+set(SNDFILE_FILE libsndfile-${SNDFILE_VERSION}.tar.gz)
set(WEBP_VERSION 0.6.1)
set(WEBP_URI https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz)
set(WEBP_HASH b49ce9c3e3e9acae4d91bca44bb85a72)
+set(WEBP_HASH_TYPE MD5)
+set(WEBP_FILE libwebp-${WEBP_VERSION}.tar.gz)
set(SPNAV_VERSION 0.2.3)
set(SPNAV_URI http://downloads.sourceforge.net/project/spacenav/spacenav%20library%20%28SDK%29/libspnav%20${SPNAV_VERSION}/libspnav-${SPNAV_VERSION}.tar.gz)
set(SPNAV_HASH 44d840540d53326d4a119c0f1aa7bf0a)
+set(SPNAV_HASH_TYPE MD5)
+set(SPNAV_FILE libspnav-${SPNAV_VERSION}.tar.gz)
set(JEMALLOC_VERSION 5.2.1)
set(JEMALLOC_URI https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/jemalloc-${JEMALLOC_VERSION}.tar.bz2)
set(JEMALLOC_HASH 3d41fbf006e6ebffd489bdb304d009ae)
+set(JEMALLOC_HASH_TYPE MD5)
+set(JEMALLOC_FILE jemalloc-${JEMALLOC_VERSION}.tar.bz2)
set(XML2_VERSION 2.9.10)
set(XML2_URI http://xmlsoft.org/sources/libxml2-${XML2_VERSION}.tar.gz)
set(XML2_HASH 10942a1dc23137a8aa07f0639cbfece5)
+set(XML2_HASH_TYPE MD5)
+set(XML2_FILE libxml2-${XML2_VERSION}.tar.gz)
set(TINYXML_VERSION 2_6_2)
set(TINYXML_VERSION_DOTS 2.6.2)
set(TINYXML_URI https://nchc.dl.sourceforge.net/project/tinyxml/tinyxml/${TINYXML_VERSION_DOTS}/tinyxml_${TINYXML_VERSION}.tar.gz)
set(TINYXML_HASH c1b864c96804a10526540c664ade67f0)
+set(TINYXML_HASH_TYPE MD5)
+set(TINYXML_FILE tinyxml_${TINYXML_VERSION}.tar.gz)
set(YAMLCPP_VERSION 0.6.3)
set(YAMLCPP_URI https://codeload.github.com/jbeder/yaml-cpp/tar.gz/yaml-cpp-${YAMLCPP_VERSION})
set(YAMLCPP_HASH b45bf1089a382e81f6b661062c10d0c2)
+set(YAMLCPP_HASH_TYPE MD5)
+set(YAMLCPP_FILE yaml-cpp-${YAMLCPP_VERSION}.tar.gz)
set(EXPAT_VERSION 2_2_10)
set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz)
set(EXPAT_HASH 7ca5f09959fcb9a57618368deb627b9f)
+set(EXPAT_HASH_TYPE MD5)
+set(EXPAT_FILE libexpat-${EXPAT_VERSION}.tar.gz)
set(PUGIXML_VERSION 1.10)
set(PUGIXML_URI https://github.com/zeux/pugixml/archive/v${PUGIXML_VERSION}.tar.gz)
set(PUGIXML_HASH 0c208b0664c7fb822bf1b49ad035e8fd)
+set(PUGIXML_HASH_TYPE MD5)
+set(PUGIXML_FILE pugixml-${PUGIXML_VERSION}.tar.gz)
set(FLEXBISON_VERSION 2.5.5)
-set(FLEXBISON_URI http://prdownloads.sourceforge.net/winflexbison/win_flex_bison-2.5.5.zip)
+set(FLEXBISON_URI http://prdownloads.sourceforge.net/winflexbison/win_flex_bison-${FLEXBISON_VERSION}.zip)
set(FLEXBISON_HASH d87a3938194520d904013abef3df10ce)
+set(FLEXBISON_HASH_TYPE MD5)
+set(FLEXBISON_FILE win_flex_bison-${FLEXBISON_VERSION}.zip)
# Libraries to keep Python modules static on Linux.
@@ -281,73 +383,107 @@ set(FLEXBISON_HASH d87a3938194520d904013abef3df10ce)
set(BZIP2_VERSION 1.0.8)
set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERSION}.orig.tar.gz)
set(BZIP2_HASH ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269)
+set(BZIP2_HASH_TYPE SHA256)
+set(BZIP2_FILE bzip2_${BZIP2_VERSION}.orig.tar.gz)
set(FFI_VERSION 3.3)
set(FFI_URI https://sourceware.org/pub/libffi/libffi-${FFI_VERSION}.tar.gz)
set(FFI_HASH 72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056)
+set(FFI_HASH_TYPE SHA256)
+set(FFI_FILE libffi-${FFI_VERSION}.tar.gz)
set(LZMA_VERSION 5.2.5)
set(LZMA_URI https://tukaani.org/xz/xz-${LZMA_VERSION}.tar.bz2)
set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df)
+set(LZMA_HASH_TYPE SHA256)
+set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2)
set(SSL_VERSION 1.1.1g)
set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46)
+set(SSL_HASH_TYPE SHA256)
+set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
set(SQLITE_VERSION 3.31.1)
set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip)
set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7)
+set(SQLITE_HASH_TYPE SHA1)
+set(SQLITE_FILE sqlite-src-3240000.zip)
set(EMBREE_VERSION 3.10.0)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
set(EMBREE_HASH 4bbe29e7eaa46417efc75fc5f1e8eb87)
+set(EMBREE_HASH_TYPE MD5)
+set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip)
set(EMBREE_ARM_GIT https://github.com/brechtvl/embree.git)
set(USD_VERSION 21.02)
set(USD_URI https://github.com/PixarAnimationStudios/USD/archive/v${USD_VERSION}.tar.gz)
set(USD_HASH 1dd1e2092d085ed393c1f7c450a4155a)
+set(USD_HASH_TYPE MD5)
+set(USD_FILE usd-v${USD_VERSION}.tar.gz)
set(OIDN_VERSION 1.3.0)
set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.tar.gz)
set(OIDN_HASH 301a5a0958d375a942014df0679b9270)
+set(OIDN_HASH_TYPE MD5)
+set(OIDN_FILE oidn-${OIDN_VERSION}.src.tar.gz)
set(LIBGLU_VERSION 9.0.1)
set(LIBGLU_URI ftp://ftp.freedesktop.org/pub/mesa/glu/glu-${LIBGLU_VERSION}.tar.xz)
set(LIBGLU_HASH 151aef599b8259efe9acd599c96ea2a3)
+set(LIBGLU_HASH_TYPE MD5)
+set(LIBGLU_FILE glu-${LIBGLU_VERSION}.tar.xz)
set(MESA_VERSION 20.3.4)
set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa/mesa-${MESA_VERSION}.tar.xz)
set(MESA_HASH 556338446aef8ae947a789b3e0b5e056)
+set(MESA_HASH_TYPE MD5)
+set(MESA_FILE mesa-${MESA_VERSION}.tar.xz)
set(NASM_VERSION 2.15.02)
set(NASM_URI https://github.com/netwide-assembler/nasm/archive/nasm-${NASM_VERSION}.tar.gz)
set(NASM_HASH aded8b796c996a486a56e0515c83e414116decc3b184d88043480b32eb0a8589)
+set(NASM_HASH_TYPE SHA256)
+set(NASM_FILE nasm-${NASM_VERSION}.tar.gz)
set(XR_OPENXR_SDK_VERSION 1.0.14)
set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz)
set(XR_OPENXR_SDK_HASH 0df6b2fd6045423451a77ff6bc3e1a75)
+set(XR_OPENXR_SDK_HASH_TYPE MD5)
+set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz)
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
# Unreleased version with macOS arm support.
set(ISPC_URI https://github.com/ispc/ispc/archive/f5949c055eb9eeb93696978a3da4bfb3a6a30b35.zip)
set(ISPC_HASH d382fea18d01dbd0cd05d9e1ede36d7d)
+ set(ISPC_HASH_TYPE MD5)
+ set(ISPC_FILE f5949c055eb9eeb93696978a3da4bfb3a6a30b35.zip)
else()
set(ISPC_VERSION v1.14.1)
set(ISPC_URI https://github.com/ispc/ispc/archive/${ISPC_VERSION}.tar.gz)
set(ISPC_HASH 968fbc8dfd16a60ba4e32d2e0e03ea7a)
+ set(ISPC_HASH_TYPE MD5)
+ set(ISPC_FILE ispc-${ISPC_VERSION}.tar.gz)
endif()
set(GMP_VERSION 6.2.0)
set(GMP_URI https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.xz)
set(GMP_HASH a325e3f09e6d91e62101e59f9bda3ec1)
+set(GMP_HASH_TYPE MD5)
+set(GMP_FILE gmp-${GMP_VERSION}.tar.xz)
set(POTRACE_VERSION 1.16)
set(POTRACE_URI http://potrace.sourceforge.net/download/${POTRACE_VERSION}/potrace-${POTRACE_VERSION}.tar.gz)
set(POTRACE_HASH 5f0bd87ddd9a620b0c4e65652ef93d69)
+set(POTRACE_HASH_TYPE MD5)
+set(POTRACE_FILE potrace-${POTRACE_VERSION}.tar.gz)
set(HARU_VERSION 2_3_0)
set(HARU_URI https://github.com/libharu/libharu/archive/RELEASE_${HARU_VERSION}.tar.gz)
set(HARU_HASH 4f916aa49c3069b3a10850013c507460)
+set(HARU_HASH_TYPE MD5)
+set(HARU_FILE libharu-${HARU_VERSION}.tar.gz)
set(SSE2NEON_GIT https://github.com/DLTcollab/sse2neon.git)
set(SSE2NEON_GIT_HASH fe5ff00bb8d19b327714a3c290f3e2ce81ba3525)
diff --git a/build_files/build_environment/cmake/vorbis.cmake b/build_files/build_environment/cmake/vorbis.cmake
index 9ef62787e86..579b4c5a298 100644
--- a/build_files/build_environment/cmake/vorbis.cmake
+++ b/build_files/build_environment/cmake/vorbis.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_vorbis
- URL ${VORBIS_URI}
+ URL file://${PACKAGE_DIR}/${VORBIS_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${VORBIS_HASH}
+ URL_HASH ${VORBIS_HASH_TYPE}=${VORBIS_HASH}
PREFIX ${BUILD_DIR}/vorbis
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/vorbis
--disable-shared
diff --git a/build_files/build_environment/cmake/vpx.cmake b/build_files/build_environment/cmake/vpx.cmake
index 799dea0189c..ab56228e81b 100644
--- a/build_files/build_environment/cmake/vpx.cmake
+++ b/build_files/build_environment/cmake/vpx.cmake
@@ -35,9 +35,9 @@ else()
endif()
ExternalProject_Add(external_vpx
- URL ${VPX_URI}
+ URL file://${PACKAGE_DIR}/${VPX_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${VPX_HASH}
+ URL_HASH ${VPX_HASH_TYPE}=${VPX_HASH}
PREFIX ${BUILD_DIR}/vpx
CONFIGURE_COMMAND ${CONFIGURE_ENV} &&
cd ${BUILD_DIR}/vpx/src/external_vpx/ &&
diff --git a/build_files/build_environment/cmake/webp.cmake b/build_files/build_environment/cmake/webp.cmake
index 7d5a5333356..61f53ca63c6 100644
--- a/build_files/build_environment/cmake/webp.cmake
+++ b/build_files/build_environment/cmake/webp.cmake
@@ -32,9 +32,9 @@ else()
endif()
ExternalProject_Add(external_webp
- URL ${WEBP_URI}
+ URL file://${PACKAGE_DIR}/${WEBP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${WEBP_HASH}
+ URL_HASH ${WEBP_HASH_TYPE}=${WEBP_HASH}
PREFIX ${BUILD_DIR}/webp
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/webp -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${WEBP_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/webp
diff --git a/build_files/build_environment/cmake/x264.cmake b/build_files/build_environment/cmake/x264.cmake
index 8daaf57a220..a32f119d184 100644
--- a/build_files/build_environment/cmake/x264.cmake
+++ b/build_files/build_environment/cmake/x264.cmake
@@ -41,9 +41,9 @@ if(UNIX AND NOT APPLE)
endif()
ExternalProject_Add(external_x264
- URL ${X264_URI}
+ URL file://${PACKAGE_DIR}/${X264_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${X264_HASH}
+ URL_HASH ${X264_HASH_TYPE}=${X264_HASH}
PREFIX ${BUILD_DIR}/x264
CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${X264_CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ &&
${CONFIGURE_COMMAND} --prefix=${LIBDIR}/x264
diff --git a/build_files/build_environment/cmake/xml2.cmake b/build_files/build_environment/cmake/xml2.cmake
index e4af71ef7c7..390ed15fccf 100644
--- a/build_files/build_environment/cmake/xml2.cmake
+++ b/build_files/build_environment/cmake/xml2.cmake
@@ -17,9 +17,9 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_xml2
- URL ${XML2_URI}
+ URL file://${PACKAGE_DIR}/${XML2_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${XML2_HASH}
+ URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH}
PREFIX ${BUILD_DIR}/xml2
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND}
--prefix=${LIBDIR}/xml2
diff --git a/build_files/build_environment/cmake/xr_openxr.cmake b/build_files/build_environment/cmake/xr_openxr.cmake
index 0ab685f8da8..f476eebe83e 100644
--- a/build_files/build_environment/cmake/xr_openxr.cmake
+++ b/build_files/build_environment/cmake/xr_openxr.cmake
@@ -35,9 +35,9 @@ if(UNIX AND NOT APPLE)
endif()
ExternalProject_Add(external_xr_openxr_sdk
- URL ${XR_OPENXR_SDK_URI}
+ URL file://${PACKAGE_DIR}/${XR_OPENXR_SDK_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${XR_OPENXR_SDK_HASH}
+ URL_HASH ${XR_OPENXR_SDK_HASH_TYPE}=${XR_OPENXR_SDK_HASH}
PREFIX ${BUILD_DIR}/xr_openxr_sdk
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/xr_openxr_sdk ${DEFAULT_CMAKE_FLAGS} ${XR_OPENXR_SDK_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/xr_openxr_sdk
diff --git a/build_files/build_environment/cmake/xvidcore.cmake b/build_files/build_environment/cmake/xvidcore.cmake
index 5ff897fcc6f..434f647f204 100644
--- a/build_files/build_environment/cmake/xvidcore.cmake
+++ b/build_files/build_environment/cmake/xvidcore.cmake
@@ -21,9 +21,9 @@ if(WIN32)
endif()
ExternalProject_Add(external_xvidcore
- URL ${XVIDCORE_URI}
+ URL file://${PACKAGE_DIR}/${XVIDCORE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH SHA256=${XVIDCORE_HASH}
+ URL_HASH ${XVIDCORE_HASH_TYPE}=${XVIDCORE_HASH}
PREFIX ${BUILD_DIR}/xvidcore
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/xvidcore ${XVIDCORE_EXTRA_ARGS}
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && make -j${MAKE_THREADS}
diff --git a/build_files/build_environment/cmake/yamlcpp.cmake b/build_files/build_environment/cmake/yamlcpp.cmake
index d56a3e4a63a..72e0cb8eac1 100644
--- a/build_files/build_environment/cmake/yamlcpp.cmake
+++ b/build_files/build_environment/cmake/yamlcpp.cmake
@@ -30,9 +30,9 @@ if(WIN32)
endif()
ExternalProject_Add(external_yamlcpp
- URL ${YAMLCPP_URI}
+ URL file://${PACKAGE_DIR}/${YAMLCPP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH MD5=${YAMLCPP_HASH}
+ URL_HASH ${YAMLCPP_HASH_TYPE}=${YAMLCPP_HASH}
PREFIX ${BUILD_DIR}/yamlcpp
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/yamlcpp ${DEFAULT_CMAKE_FLAGS} ${YAMLCPP_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/yamlcpp
diff --git a/build_files/build_environment/cmake/zlib.cmake b/build_files/build_environment/cmake/zlib.cmake
index 2b24a2d6f65..3aac5fc5334 100644
--- a/build_files/build_environment/cmake/zlib.cmake
+++ b/build_files/build_environment/cmake/zlib.cmake
@@ -17,9 +17,8 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_zlib
- URL ${ZLIB_URI}
- URL_HASH MD5=${ZLIB_HASH}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL file://${PACKAGE_DIR}/${ZLIB_FILE}
+ URL_HASH ${ZLIB_HASH_TYPE}=${ZLIB_HASH}
PREFIX ${BUILD_DIR}/zlib
CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib ${DEFAULT_CMAKE_FLAGS}
INSTALL_DIR ${LIBDIR}/zlib
diff --git a/build_files/build_environment/cmake/zlib_mingw.cmake b/build_files/build_environment/cmake/zlib_mingw.cmake
index 1a7bc1dc51b..5f5408b7f6a 100644
--- a/build_files/build_environment/cmake/zlib_mingw.cmake
+++ b/build_files/build_environment/cmake/zlib_mingw.cmake
@@ -17,8 +17,8 @@
# ***** END GPL LICENSE BLOCK *****
ExternalProject_Add(external_zlib_mingw
- URL ${ZLIB_URI}
- URL_HASH MD5=${ZLIB_HASH}
+ URL file://${PACKAGE_DIR}/${ZLIB_FILE}
+ URL_HASH ${ZLIB_HASH_TYPE}=${ZLIB_HASH}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
PREFIX ${BUILD_DIR}/zlib_mingw
CONFIGURE_COMMAND echo .
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 3b364c21f7d..7cd21b2885c 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -51,7 +51,7 @@ ARGS=$( \
getopt \
-o s:i:t:h \
--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,\
-with-all,with-opencollada,with-jack,with-embree,with-oidn,with-nanovdb,\
+with-all,with-opencollada,with-jack,with-pulseaudio,with-embree,with-oidn,with-nanovdb,\
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,ver-xr-openxr:,\
force-all,force-python,force-boost,force-tbb,\
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
@@ -157,6 +157,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--with-jack
Install the jack libraries.
+ --with-pulseaudio
+ Install the pulseaudio libraries.
+
--ver-ocio=<ver>
Force version of OCIO library.
@@ -721,6 +724,9 @@ while true; do
--with-jack)
WITH_JACK=true; shift; continue;
;;
+ --with-pulseaudio)
+ WITH_PULSEAUDIO=true; shift; continue;
+ ;;
--ver-ocio)
OCIO_VERSION="$2"
OCIO_VERSION_MIN=$OCIO_VERSION
@@ -985,6 +991,7 @@ fi
if [ "$WITH_ALL" = true ]; then
WITH_JACK=true
WITH_NANOVDB=true
+ WITH_PULSEAUDIO=true
fi
if [ "$WITH_NANOVDB" = true ]; then
@@ -3877,6 +3884,10 @@ install_DEB() {
fi
fi
+ if [ "$WITH_PULSEAUDIO" = true ]; then
+ _packages="$_packages libpulse-dev"
+ fi
+
PRINT ""
install_packages_DEB $_packages
@@ -4499,6 +4510,10 @@ install_RPM() {
_packages="$_packages jack-audio-connection-kit-devel"
fi
+ if [ "$WITH_PULSEAUDIO" = true ]; then
+ _packages="$_packages pulseaudio-libs-devel"
+ fi
+
PRINT ""
install_packages_RPM $_packages
@@ -4542,6 +4557,10 @@ install_RPM() {
X264_USE=true
fi
+ if [ "$WITH_PULSEAUDIO" = true ]; then
+ _packages="$_packages libpulse-devel"
+ fi
+
if [ "$WITH_ALL" = true ]; then
PRINT ""
XVID_DEV="libxvidcore-devel"
@@ -5073,6 +5092,10 @@ install_ARCH() {
_packages="$_packages jack2"
fi
+ if [ "$WITH_PULSEAUDIO" = true ]; then
+ _packages="$_packages libpulse"
+ fi
+
PRINT ""
install_packages_ARCH $_packages
@@ -5888,6 +5911,14 @@ print_info() {
_buildargs="$_buildargs $_1 $_2"
fi
+ if [ "$WITH_PULSEAUDIO" = true ]; then
+ _1="-D WITH_PULSEAUDIO=ON"
+ _2="-D WITH_PULSEAUDIO_DYNLOAD=ON"
+ PRINT " $_1"
+ PRINT " $_2"
+ _buildargs="$_buildargs $_1 $_2"
+ fi
+
if [ "$ALEMBIC_SKIP" = false ]; then
_1="-D WITH_ALEMBIC=ON"
PRINT " $_1"
diff --git a/build_files/build_environment/windows/build_deps.cmd b/build_files/build_environment/windows/build_deps.cmd
index 2552b74711f..2159055f3bd 100644
--- a/build_files/build_environment/windows/build_deps.cmd
+++ b/build_files/build_environment/windows/build_deps.cmd
@@ -117,7 +117,7 @@ set path=%BUILD_DIR%\downloads\mingw\mingw64\msys\1.0\bin\;%BUILD_DIR%\downloads
mkdir %STAGING%\%BuildDir%%ARCH%R
cd %Staging%\%BuildDir%%ARCH%R
echo %DATE% %TIME% : Start > %StatusFile%
-cmake -G "%CMAKE_BUILDER%" -Thost=x64 %SOURCE_DIR% -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DBUILD_MODE=Release -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/
+cmake -G "%CMAKE_BUILDER%" -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DBUILD_MODE=Release -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/
echo %DATE% %TIME% : Release Configuration done >> %StatusFile%
if "%dobuild%" == "1" (
msbuild /m "ll.vcxproj" /p:Configuration=Release /fl /flp:logfile=BlenderDeps_llvm.log;Verbosity=normal
@@ -130,7 +130,7 @@ if "%NODEBUG%" == "1" goto exit
cd %BUILD_DIR%
mkdir %STAGING%\%BuildDir%%ARCH%D
cd %Staging%\%BuildDir%%ARCH%D
-cmake -G "%CMAKE_BUILDER%" -Thost=x64 %SOURCE_DIR% -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DCMAKE_BUILD_TYPE=Debug -DBUILD_MODE=Debug -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ %CMAKE_DEBUG_OPTIONS%
+cmake -G "%CMAKE_BUILDER%" -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DCMAKE_BUILD_TYPE=Debug -DBUILD_MODE=Debug -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ %CMAKE_DEBUG_OPTIONS%
echo %DATE% %TIME% : Debug Configuration done >> %StatusFile%
if "%dobuild%" == "1" (
msbuild /m "ll.vcxproj" /p:Configuration=Debug /fl /flp:logfile=BlenderDeps_llvm.log;;Verbosity=normal
diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake
index 29004654807..20b4821959c 100644
--- a/build_files/buildbot/config/blender_linux.cmake
+++ b/build_files/buildbot/config/blender_linux.cmake
@@ -16,6 +16,7 @@ set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE)
# Options which are specific to Linux release builds only
set(WITH_JACK_DYNLOAD ON CACHE BOOL "" FORCE)
+set(WITH_PULSEAUDIO_DYNLOAD ON CACHE BOOL "" FORCE)
set(WITH_SDL_DYNLOAD ON CACHE BOOL "" FORCE)
# ######## Release environment specific settings ########
diff --git a/build_files/cmake/Modules/FindPulse.cmake b/build_files/cmake/Modules/FindPulse.cmake
new file mode 100644
index 00000000000..d5c37e7df10
--- /dev/null
+++ b/build_files/cmake/Modules/FindPulse.cmake
@@ -0,0 +1,60 @@
+# - Find PulseAudio library
+# Find the native PulseAudio includes and library
+# This module defines
+# LIBPULSE_INCLUDE_DIRS, where to find pulse/pulseaudio.h, Set when
+# LIBPULSE_INCLUDE_DIR is found.
+# LIBPULSE_LIBRARIES, libraries to link against to use PulseAudio.
+# LIBPULSE_ROOT_DIR, The base directory to search for PulseAudio.
+# This can also be an environment variable.
+# PULSE_FOUND, If false, do not try to use PulseAudio.
+#
+# also defined, but not for general use are
+# LIBPULSE_LIBRARY, where to find the PulseAudio library.
+
+#=============================================================================
+# Copyright 2021 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD 3-Clause License,
+# see accompanying file BSD-3-Clause-license.txt for details.
+#=============================================================================
+
+# If LIBPULSE_ROOT_DIR was defined in the environment, use it.
+IF(NOT LIBPULSE_ROOT_DIR AND NOT $ENV{LIBPULSE_ROOT_DIR} STREQUAL "")
+ SET(LIBPULSE_ROOT_DIR $ENV{LIBPULSE_ROOT_DIR})
+ENDIF()
+
+SET(_pulse_SEARCH_DIRS
+ ${LIBPULSE_ROOT_DIR}
+)
+
+FIND_PATH(LIBPULSE_INCLUDE_DIR pulse/pulseaudio.h
+ HINTS
+ ${_pulse_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+FIND_LIBRARY(LIBPULSE_LIBRARY
+ NAMES
+ pulse
+ HINTS
+ ${_pulse_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+ )
+
+# handle the QUIETLY and REQUIRED arguments and set PULSE_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Pulse DEFAULT_MSG
+ LIBPULSE_LIBRARY LIBPULSE_INCLUDE_DIR)
+
+IF(PULSE_FOUND)
+ SET(LIBPULSE_LIBRARIES ${LIBPULSE_LIBRARY})
+ SET(LIBPULSE_INCLUDE_DIRS ${LIBPULSE_INCLUDE_DIR})
+ENDIF()
+
+MARK_AS_ADVANCED(
+ LIBPULSE_INCLUDE_DIR
+ LIBPULSE_LIBRARY
+)
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 75f78befb60..7d8ca9ec98d 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -59,12 +59,19 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
# platform dependent options
+if(APPLE)
+ set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
+endif()
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
+if(WIN32)
+ set(WITH_WASAPI ON CACHE BOOL "" FORCE)
+endif()
if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
+ set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/config/blender_headless.cmake b/build_files/cmake/config/blender_headless.cmake
index 53163986b7a..72921c0e390 100644
--- a/build_files/cmake/config/blender_headless.cmake
+++ b/build_files/cmake/config/blender_headless.cmake
@@ -10,9 +10,12 @@ set(WITH_HEADLESS ON CACHE BOOL "" FORCE)
# disable audio, its possible some devs may want this but for now disable
# so the python module doesn't hold the audio device and loads quickly.
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
+set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
+set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
+set(WITH_WASAPI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 680734aba6e..f79bbe9d34b 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -16,6 +16,7 @@ set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE)
+set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_EMBREE OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
@@ -44,6 +45,7 @@ set(WITH_MOD_FLUID OFF CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM OFF CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
+set(WITH_WASAPI OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENIMAGEDENOISE OFF CACHE BOOL "" FORCE)
@@ -54,6 +56,7 @@ set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_POTRACE OFF CACHE BOOL "" FORCE)
set(WITH_PUGIXML OFF CACHE BOOL "" FORCE)
+set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_NANOVDB OFF CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 973d6cdb34e..7dad6d6b886 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -63,12 +63,19 @@ set(CYCLES_CUDA_BINARIES_ARCH sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61;sm_70;sm
set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
# platform dependent options
+if(APPLE)
+ set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
+endif()
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
+if(WIN32)
+ set(WITH_WASAPI ON CACHE BOOL "" FORCE)
+endif()
if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
+ set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/config/bpy_module.cmake b/build_files/cmake/config/bpy_module.cmake
index 7fc68f97f29..087fdd87649 100644
--- a/build_files/cmake/config/bpy_module.cmake
+++ b/build_files/cmake/config/bpy_module.cmake
@@ -15,9 +15,12 @@ set(WITH_PYTHON_INSTALL OFF CACHE BOOL "" FORCE)
# disable audio, its possible some devs may want this but for now disable
# so the python module doesn't hold the audio device and loads quickly.
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
+set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
+set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
+set(WITH_WASAPI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index cad1d86b75a..813ac013cdf 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -569,6 +569,9 @@ function(SETUP_LIBDIRS)
if(WITH_JACK AND NOT WITH_JACK_DYNLOAD)
link_directories(${JACK_LIBPATH})
endif()
+ if(WITH_PULSEAUDIO AND NOT WITH_PULSEAUDIO_DYNLOAD)
+ link_directories(${LIBPULSE_LIBPATH})
+ endif()
if(WITH_CODEC_SNDFILE)
link_directories(${LIBSNDFILE_LIBPATH})
endif()
diff --git a/build_files/cmake/platform/platform_apple_xcode.cmake b/build_files/cmake/platform/platform_apple_xcode.cmake
index 43bdafb8ce2..4d15fee75b7 100644
--- a/build_files/cmake/platform/platform_apple_xcode.cmake
+++ b/build_files/cmake/platform/platform_apple_xcode.cmake
@@ -66,7 +66,7 @@ endif()
if(XCODE_VERSION)
# Construct SDKs path ourselves, because xcode-select path could be ambiguous.
# Both /Applications/Xcode.app/Contents/Developer or /Applications/Xcode.app would be allowed.
- set(XCODE_SDK_DIR ${XCODE_DEVELOPER_DIR}/Platforms/MacOSX.platform//Developer/SDKs)
+ set(XCODE_SDK_DIR ${XCODE_DEVELOPER_DIR}/Platforms/MacOSX.platform/Developer/SDKs)
# Detect SDK version to use
if(NOT DEFINED OSX_SYSTEM)
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 47c788c7eb6..7791112c6ab 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -552,6 +552,14 @@ if(WITH_JACK)
endif()
endif()
+# Pulse is intended to use the system library.
+if(WITH_PULSEAUDIO)
+ find_package_wrapper(Pulse)
+ if(NOT PULSE_FOUND)
+ set(WITH_PULSEAUDIO OFF)
+ endif()
+endif()
+
# Audio IO
if(WITH_SYSTEM_AUDASPACE)
find_package_wrapper(Audaspace)
diff --git a/build_files/utils/make_source_archive.py b/build_files/utils/make_source_archive.py
new file mode 100755
index 00000000000..271ca358f7e
--- /dev/null
+++ b/build_files/utils/make_source_archive.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python3
+
+import dataclasses
+import os
+import re
+import subprocess
+from pathlib import Path
+from typing import Iterable, TextIO
+
+# This script can run from any location,
+# output is created in the $CWD
+#
+# NOTE: while the Python part of this script is portable,
+# it relies on external commands typically found on GNU/Linux.
+# Support for other platforms could be added by moving GNU `tar` & `md5sum` use to Python.
+
+SKIP_NAMES = {
+ ".gitignore",
+ ".gitmodules",
+ ".arcconfig",
+}
+
+
+def main() -> None:
+ output_dir = Path(".").absolute()
+ blender_srcdir = Path(__file__).absolute().parent.parent.parent
+ print(f"Source dir: {blender_srcdir}")
+
+ version = parse_blender_version(blender_srcdir)
+ manifest = output_dir / f"blender-{version}-manifest.txt"
+ tarball = output_dir / f"blender-{version}.tar.xz"
+
+ os.chdir(blender_srcdir)
+ create_manifest(version, manifest)
+ create_tarball(version, tarball, manifest)
+ create_checksum_file(tarball)
+ cleanup(manifest)
+ print("Done!")
+
+
+@dataclasses.dataclass
+class BlenderVersion:
+ version: int # 293 for 2.93.1
+ patch: int # 1 for 2.93.1
+ cycle: str # 'alpha', 'beta', 'release', maybe others.
+
+ @property
+ def is_release(self) -> bool:
+ return self.cycle == "release"
+
+ def __str__(self) -> str:
+ """Convert to version string.
+
+ >>> str(BlenderVersion(293, 1, "alpha"))
+ '2.93.1-alpha'
+ >>> str(BlenderVersion(327, 0, "release"))
+ '3.27.0'
+ """
+ version_major = self.version // 100
+ version_minor = self.version % 100
+ as_string = f"{version_major}.{version_minor}.{self.patch}"
+ if self.is_release:
+ return as_string
+ return f"{as_string}-{self.cycle}"
+
+
+def parse_blender_version(blender_srcdir: Path) -> BlenderVersion:
+ version_path = blender_srcdir / "source/blender/blenkernel/BKE_blender_version.h"
+
+ version_info = {}
+ line_re = re.compile(r"^#define (BLENDER_VERSION[A-Z_]*)\s+([0-9a-z]+)$")
+
+ with version_path.open(encoding="utf-8") as version_file:
+ for line in version_file:
+ match = line_re.match(line.strip())
+ if not match:
+ continue
+ version_info[match.group(1)] = match.group(2)
+
+ return BlenderVersion(
+ int(version_info["BLENDER_VERSION"]),
+ int(version_info["BLENDER_VERSION_PATCH"]),
+ version_info["BLENDER_VERSION_CYCLE"],
+ )
+
+
+### Manifest creation
+
+
+def create_manifest(version: BlenderVersion, outpath: Path) -> None:
+ print(f'Building manifest of files: "{outpath}"...', end="", flush=True)
+ with outpath.open("w", encoding="utf-8") as outfile:
+ main_files_to_manifest(outfile)
+ submodules_to_manifest(version, outfile)
+ print("OK")
+
+
+def main_files_to_manifest(outfile: TextIO) -> None:
+ for path in git_ls_files():
+ print(path, file=outfile)
+
+
+def submodules_to_manifest(version: BlenderVersion, outfile: TextIO) -> None:
+ skip_addon_contrib = version.is_release
+
+ for line in git_command("submodule"):
+ submodule = line.split()[1]
+
+ # Don't use native slashes as GIT for MS-Windows outputs forward slashes.
+ if skip_addon_contrib and submodule == "release/scripts/addons_contrib":
+ continue
+
+ for path in git_ls_files(Path(submodule)):
+ print(path, file=outfile)
+
+
+def create_tarball(version: BlenderVersion, tarball: Path, manifest: Path) -> None:
+ print(f'Creating archive: "{tarball}" ...', end="", flush=True)
+ # Requires GNU `tar`, since `--transform` is used.
+ command = [
+ "tar",
+ "--transform",
+ f"s,^,blender-{version}/,g",
+ "--use-compress-program=xz -9",
+ "--create",
+ f"--file={tarball}",
+ f"--files-from={manifest}",
+ # Without owner/group args, extracting the files as root will
+ # use ownership from the tar archive:
+ "--owner=0",
+ "--group=0",
+ ]
+ subprocess.run(command, check=True, timeout=300)
+ print("OK")
+
+
+def create_checksum_file(tarball: Path) -> None:
+ md5_path = tarball.with_name(tarball.name + ".md5sum")
+ print(f'Creating checksum: "{md5_path}" ...', end="", flush=True)
+ command = [
+ "md5sum",
+ # The name is enough, as the tarball resides in the same dir as the MD5
+ # file, and that's the current working directory.
+ tarball.name,
+ ]
+ md5_cmd = subprocess.run(
+ command, stdout=subprocess.PIPE, check=True, text=True, timeout=300
+ )
+ with md5_path.open("w", encoding="utf-8") as outfile:
+ outfile.write(md5_cmd.stdout)
+ print("OK")
+
+
+def cleanup(manifest: Path) -> None:
+ print("Cleaning up ...", end="", flush=True)
+ if manifest.exists():
+ manifest.unlink()
+ print("OK")
+
+
+## Low-level commands
+
+
+def git_ls_files(directory: Path = Path(".")) -> Iterable[Path]:
+ """Generator, yields lines of output from 'git ls-files'.
+
+ Only lines that are actually files (so no directories, sockets, etc.) are
+ returned, and never one from SKIP_NAMES.
+ """
+ for line in git_command("-C", str(directory), "ls-files"):
+ path = directory / line
+ if not path.is_file() or path.name in SKIP_NAMES:
+ continue
+ yield path
+
+
+def git_command(*cli_args) -> Iterable[str]:
+ """Generator, yields lines of output from a Git command."""
+ command = ("git", *cli_args)
+
+ # import shlex
+ # print(">", " ".join(shlex.quote(arg) for arg in command))
+
+ git = subprocess.run(
+ command, stdout=subprocess.PIPE, check=True, text=True, timeout=30
+ )
+ for line in git.stdout.split("\n"):
+ if line:
+ yield line
+
+
+if __name__ == "__main__":
+ import doctest
+
+ if doctest.testmod().failed:
+ raise SystemExit("ERROR: Self-test failed, refusing to run")
+
+ main()
diff --git a/build_files/utils/make_source_archive.sh b/build_files/utils/make_source_archive.sh
deleted file mode 100755
index 5d9096f3235..00000000000
--- a/build_files/utils/make_source_archive.sh
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/bin/sh
-
-# This script can run from any location,
-# output is created in the $CWD
-
-BASE_DIR="$PWD"
-
-blender_srcdir=$(dirname -- $0)/../..
-blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
-blender_version_patch=$(grep "BLENDER_VERSION_PATCH\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
-blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
-
-VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100).$blender_version_patch
-if [ "$blender_version_cycle" = "release" ] ; then
- SUBMODULE_EXCLUDE="^\(release/scripts/addons_contrib\)$"
-else
- VERSION=$VERSION-$blender_version_cycle
- SUBMODULE_EXCLUDE="^$" # dummy regex
-fi
-
-MANIFEST="blender-$VERSION-manifest.txt"
-TARBALL="blender-$VERSION.tar.xz"
-
-cd "$blender_srcdir"
-
-# not so nice, but works
-FILTER_FILES_PY=\
-"import os, sys; "\
-"[print(l[:-1]) for l in sys.stdin.readlines() "\
-"if os.path.isfile(l[:-1]) "\
-"if os.path.basename(l[:-1]) not in {"\
-"'.gitignore', "\
-"'.gitmodules', "\
-"'.arcconfig', "\
-"}"\
-"]"
-
-# Build master list
-echo -n "Building manifest of files: \"$BASE_DIR/$MANIFEST\" ..."
-git ls-files | python3 -c "$FILTER_FILES_PY" > $BASE_DIR/$MANIFEST
-
-# Enumerate submodules
-for lcv in $(git submodule | awk '{print $2}' | grep -v "$SUBMODULE_EXCLUDE"); do
- cd "$BASE_DIR"
- cd "$blender_srcdir/$lcv"
- git ls-files | python3 -c "$FILTER_FILES_PY" | awk '$0="'"$lcv"/'"$0' >> $BASE_DIR/$MANIFEST
- cd "$BASE_DIR"
-done
-echo "OK"
-
-
-# Create the tarball
-#
-# Without owner/group args, extracting the files as root will
-# use ownership from the tar archive.
-cd "$blender_srcdir"
-echo -n "Creating archive: \"$BASE_DIR/$TARBALL\" ..."
-tar \
- --transform "s,^,blender-$VERSION/,g" \
- --use-compress-program="xz -9" \
- --create \
- --file="$BASE_DIR/$TARBALL" \
- --files-from="$BASE_DIR/$MANIFEST" \
- --owner=0 \
- --group=0
-
-echo "OK"
-
-
-# Create checksum file
-cd "$BASE_DIR"
-echo -n "Creating checksum: \"$BASE_DIR/$TARBALL.md5sum\" ..."
-md5sum "$TARBALL" > "$TARBALL.md5sum"
-echo "OK"
-
-
-# Cleanup
-echo -n "Cleaning up ..."
-rm "$BASE_DIR/$MANIFEST"
-echo "OK"
-
-echo "Done!"
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index 98fb039c90b..b08b868a7e3 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -54,12 +54,21 @@
* \ingroup intern undoc
* \todo add to doxygen
*/
+/** \defgroup audcoreaudio Audaspace CoreAudio
+ * \ingroup audaspace
+ */
/** \defgroup audfx Audaspace FX
* \ingroup audaspace
*/
/** \defgroup audopenal Audaspace OpenAL
* \ingroup audaspace
*/
+/** \defgroup audpulseaudio Audaspace PulseAudio
+ * \ingroup audaspace
+ */
+/** \defgroup audwasapi Audaspace WASAPI
+ * \ingroup audaspace
+ */
/** \defgroup audpython Audaspace Python
* \ingroup audaspace
*/
diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt
index 84f5e8441c1..fe1bf5dc742 100644
--- a/extern/audaspace/CMakeLists.txt
+++ b/extern/audaspace/CMakeLists.txt
@@ -284,6 +284,15 @@ if(AUDASPACE_STANDALONE)
option(WITH_PYTHON "Build With Python Library" TRUE)
option(WITH_SDL "Build With SDL" TRUE)
option(WITH_STRICT_DEPENDENCIES "Error and abort instead of warning if a library is not found." FALSE)
+ if(APPLE)
+ option(WITH_COREAUDIO "Build With CoreAudio" TRUE)
+ endif()
+ if(NOT WIN32 AND NOT APPLE)
+ option(WITH_PULSEAUDIO "Build With PulseAudio" TRUE)
+ endif()
+ if(WIN32)
+ option(WITH_WASAPI "Build With WASAPI" TRUE)
+ endif()
if(WITH_STRICT_DEPENDENCIES)
set(PACKAGE_OPTION REQUIRED)
@@ -291,7 +300,7 @@ if(AUDASPACE_STANDALONE)
endif()
if(AUDASPACE_STANDALONE)
- if(WIN32)
+ if(WIN32 OR APPLE)
set(DEFAULT_PLUGIN_PATH "." CACHE STRING "Default plugin installation and loading path.")
set(DOCUMENTATION_INSTALL_PATH "doc" CACHE PATH "Path where the documentation is installed.")
else()
@@ -302,14 +311,18 @@ endif()
if(AUDASPACE_STANDALONE)
cmake_dependent_option(SEPARATE_C "Build C Binding as separate library" TRUE "WITH_C" FALSE)
+ cmake_dependent_option(PLUGIN_COREAUDIO "Build CoreAudio Plugin" TRUE "WITH_COREAUDIO;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_FFMPEG "Build FFMPEG Plugin" TRUE "WITH_FFMPEG;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_JACK "Build JACK Plugin" TRUE "WITH_JACK;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_LIBSNDFILE "Build LibSndFile Plugin" TRUE "WITH_LIBSNDFILE;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_OPENAL "Build OpenAL Plugin" TRUE "WITH_OPENAL;SHARED_LIBRARY" FALSE)
+ cmake_dependent_option(PLUGIN_PULSEAUDIO "Build PulseAudio Plugin" TRUE "WITH_PULSEAUDIO;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_SDL "Build SDL Plugin" TRUE "WITH_SDL;SHARED_LIBRARY" FALSE)
+ cmake_dependent_option(PLUGIN_WASAPI "Build WASAPI Plugin" TRUE "WITH_WASAPI;SHARED_LIBRARY" FALSE)
cmake_dependent_option(WITH_PYTHON_MODULE "Build Python Module" TRUE "WITH_PYTHON" FALSE)
cmake_dependent_option(USE_SDL2 "Use SDL2 instead of 1 if available" TRUE "WITH_SDL" FALSE)
cmake_dependent_option(DYNLOAD_JACK "Dynamically load JACK" FALSE "WITH_JACK" FALSE)
+ cmake_dependent_option(DYNLOAD_PULSEAUDIO "Dynamically load PulseAudio" FALSE "WITH_PULSEAUDIO" FALSE)
cmake_dependent_option(WITH_BINDING_DOCS "Build C/Python HTML Documentation with Sphinx" TRUE "WITH_PYTHON_MODULE" FALSE)
endif()
@@ -380,16 +393,16 @@ if(WITH_C)
bindings/C/AUD_Types.h
)
-if(WITH_FFTW)
- list(APPEND C_SRC
+ if(WITH_FFTW)
+ list(APPEND C_SRC
bindings/C/AUD_HRTF.cpp
bindings/C/AUD_ImpulseResponse.cpp
- )
+ )
list(APPEND C_HDR
bindings/C/AUD_HRTF.h
bindings/C/AUD_ImpulseResponse.h
- )
+ )
endif()
if(NOT SEPARATE_C)
@@ -400,6 +413,44 @@ if(WITH_FFTW)
endif()
endif()
+# CoreAudio
+if(WITH_COREAUDIO)
+ find_library(COREAUDIO_LIBRARY CoreAudio)
+ find_library(AUDIOUNIT_LIBRARY AudioUnit)
+ find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
+ find_path(AUDIOUNIT_INCLUDE_DIR AudioUnit/AudioUnit.h)
+ find_path(AUDIOTOOLBOX_INCLUDE_DIR AudioToolbox/CoreAudioClock.h)
+
+ if(COREAUDIO_LIBRARY AND AUDIOUNIT_LIBRARY AND AUDIOUNIT_INCLUDE_DIR)
+ set(COREAUDIO_LIBRARIES ${COREAUDIO_LIBRARY} ${AUDIOUNIT_LIBRARY} ${AUDIOTOOLBOX_LIBRARY})
+ set(COREAUDIO_INCLUDE_DIRS ${AUDIOUNIT_INCLUDE_DIR} ${AUDIOTOOLBOX_INCLUDE_DIR})
+
+ set(COREAUDIO_SRC
+ plugins/coreaudio/CoreAudioDevice.cpp
+ plugins/coreaudio/CoreAudioSynchronizer.cpp
+ )
+ set(COREAUDIO_HDR
+ plugins/coreaudio/CoreAudioDevice.h
+ plugins/coreaudio/CoreAudioSynchronizer.h
+ )
+
+ if(NOT PLUGIN_COREAUDIO)
+ list(APPEND INCLUDE ${COREAUDIO_INCLUDE_DIRS})
+ list(APPEND LIBRARIES ${COREAUDIO_LIBRARIES})
+ list(APPEND SRC ${COREAUDIO_SRC})
+ list(APPEND HDR ${COREAUDIO_HDR})
+ list(APPEND STATIC_PLUGINS CoreAudioDevice)
+ endif()
+ else()
+ if(WITH_STRICT_DEPENDENCIES)
+ message(FATAL_ERROR "CoreAudio not found!")
+ else()
+ set(WITH_COREAUDIO FALSE CACHE BOOL "Build With CoreAudio" FORCE)
+ message(WARNING "CoreAudio not found, plugin will not be built.")
+ endif()
+ endif()
+endif()
+
# FFMPEG
if(WITH_FFMPEG)
if(AUDASPACE_STANDALONE)
@@ -504,7 +555,7 @@ if(WITH_JACK)
plugins/jack/JackSymbols.h
)
- if(DYNLOAD_JACK)
+ if(DYNLOAD_JACK)
add_definitions(-DDYNLOAD_JACK)
endif()
@@ -598,6 +649,42 @@ if(WITH_OPENAL)
endif()
endif()
+# PulseAudio
+if(WITH_PULSEAUDIO)
+ if(AUDASPACE_STANDALONE)
+ find_package(LibPulse ${PACKAGE_OPTION})
+ endif()
+
+ if(LIBPULSE_FOUND)
+ set(PULSEAUDIO_SRC
+ plugins/pulseaudio/PulseAudioDevice.cpp
+ plugins/pulseaudio/PulseAudioLibrary.cpp
+ )
+ set(PULSEAUDIO_HDR
+ plugins/pulseaudio/PulseAudioDevice.h
+ plugins/pulseaudio/PulseAudioLibrary.h
+ plugins/pulseaudio/PulseAudioSymbols.h
+ )
+
+ if(DYNLOAD_PULSEAUDIO)
+ add_definitions(-DDYNLOAD_PULSEAUDIO)
+ endif()
+
+ if(NOT PLUGIN_PULSEAUDIO)
+ list(APPEND INCLUDE ${LIBPULSE_INCLUDE_DIR})
+ if(NOT DYNLOAD_PULSEAUDIO)
+ list(APPEND LIBRARIES ${LIBPULSE_LIBRARY})
+ endif()
+ list(APPEND SRC ${PULSEAUDIO_SRC})
+ list(APPEND HDR ${PULSEAUDIO_HDR})
+ list(APPEND STATIC_PLUGINS PulseAudioDevice)
+ endif()
+ else()
+ set(WITH_PULSEAUDIO FALSE CACHE BOOL "Build With PulseAudio" FORCE)
+ message(WARNING "PulseAudio not found, plugin will not be built.")
+ endif()
+endif()
+
# Python
if(WITH_PYTHON)
if(AUDASPACE_STANDALONE)
@@ -672,6 +759,23 @@ if(WITH_SDL)
endif()
endif()
+# WASAPI
+if(WITH_WASAPI)
+ set(WASAPI_SRC
+ plugins/wasapi/WASAPIDevice.cpp
+ )
+ set(WASAPI_HDR
+ plugins/wasapi/WASAPIDevice.h
+ )
+
+ if(NOT PLUGIN_WASAPI)
+ list(APPEND LIBRARIES ksuser)
+ list(APPEND SRC ${WASAPI_SRC})
+ list(APPEND HDR ${WASAPI_HDR})
+ list(APPEND STATIC_PLUGINS WASAPIDevice)
+ endif()
+endif()
+
# library configuration
if(SHARED_LIBRARY)
@@ -757,6 +861,17 @@ endif()
# plugins
+if(WITH_COREAUDIO AND PLUGIN_COREAUDIO)
+ add_definitions(-DCOREAUDIO_PLUGIN)
+ include_directories(${INCLUDE} ${COREAUDIO_INCLUDE_DIRS})
+ add_library(audcoreaudio SHARED ${COREAUDIO_SRC} ${COREAUDIO_HDR} ${HDR})
+ if(WITH_VERSIONED_PLUGINS)
+ set_target_properties(audcoreaudio PROPERTIES SOVERSION ${AUDASPACE_VERSION})
+ endif()
+ target_link_libraries(audcoreaudio audaspace ${COREAUDIO_LIBRARIES})
+ install(TARGETS audcoreaudio DESTINATION ${DEFAULT_PLUGIN_PATH})
+endif()
+
if(WITH_FFMPEG AND PLUGIN_FFMPEG)
add_definitions(-DFFMPEG_PLUGIN)
include_directories(${INCLUDE} ${FFMPEG_INCLUDE_DIRS})
@@ -797,6 +912,19 @@ if(WITH_OPENAL AND PLUGIN_OPENAL)
install(TARGETS audopenal DESTINATION ${DEFAULT_PLUGIN_PATH})
endif()
+if(WITH_PULSEAUDIO AND PLUGIN_PULSEAUDIO)
+ add_definitions(-DPULSEAUDIO_PLUGIN)
+ include_directories(${INCLUDE} ${LIBPULSE_INCLUDE_DIR})
+ add_library(audpulseaudio SHARED ${PULSEAUDIO_SRC} ${PULSEAUDIO_HDR} ${HDR})
+ set_target_properties(audpulseaudio PROPERTIES SOVERSION ${AUDASPACE_VERSION})
+ if(DYNLOAD_PULSEAUDIO)
+ target_link_libraries(audpulseaudio audaspace)
+ else()
+ target_link_libraries(audpulseaudio audaspace ${LIBPULSE_LIBRARY})
+ endif()
+ install(TARGETS audpulseaudio DESTINATION ${DEFAULT_PLUGIN_PATH})
+endif()
+
if(WITH_SDL AND PLUGIN_SDL)
add_definitions(-DSDL_PLUGIN)
include_directories(${INCLUDE} ${SDL_INCLUDE_DIR})
@@ -806,6 +934,17 @@ if(WITH_SDL AND PLUGIN_SDL)
install(TARGETS audsdl DESTINATION ${DEFAULT_PLUGIN_PATH})
endif()
+if(WITH_WASAPI AND PLUGIN_WASAPI)
+ add_definitions(-DWASAPI_PLUGIN)
+ include_directories(${INCLUDE})
+ add_library(audwasapi SHARED ${WASAPI_SRC} ${WASAPI_HDR} ${HDR})
+ if(WITH_VERSIONED_PLUGINS)
+ set_target_properties(audwasapi PROPERTIES SOVERSION ${AUDASPACE_VERSION})
+ endif()
+ target_link_libraries(audwasapi audaspace ksuser)
+ install(TARGETS audwasapi DESTINATION ${DEFAULT_PLUGIN_PATH})
+endif()
+
# dlls
if(WIN32)
diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp
index a83465620ab..ac876a01eb3 100644
--- a/extern/audaspace/bindings/C/AUD_Special.cpp
+++ b/extern/audaspace/bindings/C/AUD_Special.cpp
@@ -376,7 +376,7 @@ AUD_API AUD_Device* AUD_init(const char* device, AUD_DeviceSpecs specs, int buff
{
try
{
- std::shared_ptr<IDeviceFactory> factory = DeviceManager::getDeviceFactory(device);
+ std::shared_ptr<IDeviceFactory> factory = device ? DeviceManager::getDeviceFactory(device) : DeviceManager::getDefaultDeviceFactory();
if(factory)
{
diff --git a/extern/audaspace/blender_config.cmake b/extern/audaspace/blender_config.cmake
index 12810e2b044..14d7d593838 100644
--- a/extern/audaspace/blender_config.cmake
+++ b/extern/audaspace/blender_config.cmake
@@ -10,19 +10,24 @@ set(WITH_FFMPEG ${WITH_CODEC_FFMPEG}) # "Build With FFMPEG"
set(WITH_FFTW FALSE) # "Build With FFTW"
set(WITH_LIBSNDFILE ${WITH_CODEC_SNDFILE}) # "Build With LibSndFile"
set(SEPARATE_C FALSE) # "Build C Binding as separate library"
+set(PLUGIN_COREAUDIO FALSE) # "Build CoreAudio Plugin"
set(PLUGIN_FFMPEG FALSE) # "Build FFMPEG Plugin"
set(PLUGIN_JACK FALSE) # "Build JACK Plugin"
set(PLUGIN_LIBSNDFILE FALSE) # "Build LibSndFile Plugin"
set(PLUGIN_OPENAL FALSE) # "Build OpenAL Plugin"
+set(PLUGIN_PULSEAUDIO FALSE) # "Build PulseAudio Plugin"
set(PLUGIN_SDL FALSE) # "Build SDL Plugin"
+set(PLUGIN_WASAPI FALSE) # "Build WASAPI Plugin"
set(WITH_PYTHON_MODULE FALSE) # "Build Python Module"
set(DYNLOAD_JACK ${WITH_JACK_DYNLOAD}) # "Dynamically load JACK"
+set(DYNLOAD_PULSEAUDIO ${WITH_PULSEAUDIO_DYNLOAD}) # "Dynamically load PulseAudio"
set(WITH_BINDING_DOCS FALSE) # "Build C/Python HTML Documentation with Sphinx"
set(DEFAULT_PLUGIN_PATH "plugins") # "Default plugin installation and loading path."
set(FFMPEG_FOUND ${WITH_CODEC_FFMPEG})
set(JACK_FOUND ${WITH_JACK})
set(LIBSNDFILE_FOUND ${WITH_CODEC_SNDFILE})
set(OPENAL_FOUND ${WITH_OPENAL})
+set(LIBPULSE_FOUND ${WITH_PULSEAUDIO})
set(PYTHONLIBS_FOUND TRUE)
set(NUMPY_FOUND ${WITH_PYTHON_NUMPY})
set(NUMPY_INCLUDE_DIRS ${PYTHON_NUMPY_INCLUDE_DIRS})
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp
new file mode 100644
index 00000000000..113ceccad60
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright 2009-2021 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "CoreAudioDevice.h"
+#include "devices/DeviceManager.h"
+#include "devices/IDeviceFactory.h"
+#include "Exception.h"
+#include "IReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+OSStatus CoreAudioDevice::CoreAudio_mix(void* data, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time_stamp, UInt32 bus_number, UInt32 number_frames, AudioBufferList* buffer_list)
+{
+ CoreAudioDevice* device = (CoreAudioDevice*)data;
+
+ for(int i = 0; i < buffer_list->mNumberBuffers; i++)
+ {
+ auto& buffer = buffer_list->mBuffers[i];
+
+ device->mix((data_t*)buffer.mData, buffer.mDataByteSize / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
+ }
+
+ return noErr;
+}
+
+void CoreAudioDevice::playing(bool playing)
+{
+ if(m_playback != playing)
+ {
+ if(playing)
+ AudioOutputUnitStart(m_audio_unit);
+ else
+ AudioOutputUnitStop(m_audio_unit);
+ }
+
+ m_playback = playing;
+}
+
+CoreAudioDevice::CoreAudioDevice(DeviceSpecs specs, int buffersize) :
+m_playback(false),
+m_audio_unit(nullptr)
+{
+ AudioComponentDescription component_description = {};
+
+ component_description.componentType = kAudioUnitType_Output;
+ component_description.componentSubType = kAudioUnitSubType_DefaultOutput;
+ component_description.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+ AudioComponent component = AudioComponentFindNext(nullptr, &component_description);
+
+ if(!component)
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+
+ OSStatus status = AudioComponentInstanceNew(component, &m_audio_unit);
+
+ if(status != noErr)
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+
+ AudioStreamBasicDescription stream_basic_description = {};
+
+ if(specs.channels == CHANNELS_INVALID)
+ specs.channels = CHANNELS_STEREO;
+ if(specs.format == FORMAT_INVALID)
+ specs.format = FORMAT_FLOAT32;
+ if(specs.rate == RATE_INVALID)
+ specs.rate = RATE_48000;
+
+ switch(specs.format)
+ {
+ case FORMAT_U8:
+ stream_basic_description.mFormatFlags = 0;
+ stream_basic_description.mBitsPerChannel = 8;
+ break;
+ case FORMAT_S16:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
+ stream_basic_description.mBitsPerChannel = 16;
+ break;
+ case FORMAT_S24:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
+ stream_basic_description.mBitsPerChannel = 24;
+ break;
+ case FORMAT_S32:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
+ stream_basic_description.mBitsPerChannel = 32;
+ break;
+ case FORMAT_FLOAT32:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsFloat;
+ stream_basic_description.mBitsPerChannel = 32;
+ break;
+ case FORMAT_FLOAT64:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsFloat;
+ stream_basic_description.mBitsPerChannel = 64;
+ break;
+ default:
+ specs.format = FORMAT_FLOAT32;
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsFloat;
+ stream_basic_description.mBitsPerChannel = 32;
+ break;
+ }
+
+ stream_basic_description.mSampleRate = specs.rate;
+ stream_basic_description.mFormatID = kAudioFormatLinearPCM;
+ stream_basic_description.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
+ stream_basic_description.mBytesPerPacket = stream_basic_description.mBytesPerFrame = AUD_DEVICE_SAMPLE_SIZE(specs);
+ stream_basic_description.mFramesPerPacket = 1;
+ stream_basic_description.mChannelsPerFrame = specs.channels;
+
+ status = AudioUnitSetProperty(m_audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &stream_basic_description, sizeof(stream_basic_description));
+
+ if(status != noErr)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+ }
+
+ m_specs = specs;
+
+ AURenderCallbackStruct render_callback_struct;
+ render_callback_struct.inputProc = CoreAudioDevice::CoreAudio_mix;
+ render_callback_struct.inputProcRefCon = this;
+
+ status = AudioUnitSetProperty(m_audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &render_callback_struct, sizeof(render_callback_struct));
+
+ if(status != noErr)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+ }
+
+ status = AudioUnitInitialize(m_audio_unit);
+
+ if(status != noErr)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+ }
+
+ try
+ {
+ m_synchronizer = std::unique_ptr<CoreAudioSynchronizer>(new CoreAudioSynchronizer(m_audio_unit));
+ }
+ catch(Exception&)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ throw;
+ }
+
+ create();
+}
+
+CoreAudioDevice::~CoreAudioDevice()
+{
+ AudioOutputUnitStop(m_audio_unit);
+ AudioUnitUninitialize(m_audio_unit);
+ AudioComponentInstanceDispose(m_audio_unit);
+
+ destroy();
+}
+
+ISynchronizer* CoreAudioDevice::getSynchronizer()
+{
+ return m_synchronizer.get();
+}
+
+class CoreAudioDeviceFactory : public IDeviceFactory
+{
+private:
+ DeviceSpecs m_specs;
+ int m_buffersize;
+
+public:
+ CoreAudioDeviceFactory() :
+ m_buffersize(AUD_DEFAULT_BUFFER_SIZE)
+ {
+ m_specs.format = FORMAT_FLOAT32;
+ m_specs.channels = CHANNELS_STEREO;
+ m_specs.rate = RATE_48000;
+ }
+
+ virtual std::shared_ptr<IDevice> openDevice()
+ {
+ return std::shared_ptr<IDevice>(new CoreAudioDevice(m_specs, m_buffersize));
+ }
+
+ virtual int getPriority()
+ {
+ return 1 << 15;
+ }
+
+ virtual void setSpecs(DeviceSpecs specs)
+ {
+ m_specs = specs;
+ }
+
+ virtual void setBufferSize(int buffersize)
+ {
+ m_buffersize = buffersize;
+ }
+
+ virtual void setName(std::string name)
+ {
+ }
+};
+
+void CoreAudioDevice::registerPlugin()
+{
+ DeviceManager::registerDevice("CoreAudio", std::shared_ptr<IDeviceFactory>(new CoreAudioDeviceFactory));
+}
+
+#ifdef COREAUDIO_PLUGIN
+extern "C" AUD_PLUGIN_API void registerPlugin()
+{
+ CoreAudioDevice::registerPlugin();
+}
+
+extern "C" AUD_PLUGIN_API const char* getName()
+{
+ return "CoreAudio";
+}
+#endif
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioDevice.h b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.h
new file mode 100644
index 00000000000..3770228db6f
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.h
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright 2009-2021 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef COREAUDIO_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file CoreAudioDevice.h
+ * @ingroup plugin
+ * The CoreAudioDevice class.
+ */
+
+#include "CoreAudioSynchronizer.h"
+#include "devices/SoftwareDevice.h"
+
+#include <memory>
+
+#include <AudioUnit/AudioUnit.h>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This device plays back through CoreAudio, the Apple audio API.
+ */
+class AUD_PLUGIN_API CoreAudioDevice : public SoftwareDevice
+{
+private:
+ /**
+ * Whether there is currently playback.
+ */
+ bool m_playback;
+
+ /**
+ * The CoreAudio AudioUnit.
+ */
+ AudioUnit m_audio_unit;
+
+ /**
+ * The Synchronizer.
+ */
+ std::unique_ptr<CoreAudioSynchronizer> m_synchronizer;
+
+ /**
+ * Mixes the next bytes into the buffer.
+ * \param data The CoreAudio device.
+ * \param flags Unused flags.
+ * \param time_stamp Unused time stamp.
+ * \param bus_number Unused bus number.
+ * \param number_frames Unused number of frames.
+ * \param buffer_list The list of buffers to be filled.
+ */
+ AUD_LOCAL static OSStatus CoreAudio_mix(void* data, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time_stamp, UInt32 bus_number, UInt32 number_frames, AudioBufferList* buffer_list);
+
+ // delete copy constructor and operator=
+ CoreAudioDevice(const CoreAudioDevice&) = delete;
+ CoreAudioDevice& operator=(const CoreAudioDevice&) = delete;
+
+protected:
+ virtual void playing(bool playing);
+
+public:
+ /**
+ * Opens the CoreAudio audio device for playback.
+ * \param specs The wanted audio specification.
+ * \param buffersize The size of the internal buffer.
+ * \note The specification really used for opening the device may differ.
+ * \exception Exception Thrown if the audio device cannot be opened.
+ */
+ CoreAudioDevice(DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
+
+ /**
+ * Closes the CoreAudio audio device.
+ */
+ virtual ~CoreAudioDevice();
+
+ virtual ISynchronizer* getSynchronizer();
+
+ /**
+ * Registers this plugin.
+ */
+ static void registerPlugin();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp
new file mode 100644
index 00000000000..fcfa7fde9be
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "CoreAudioSynchronizer.h"
+
+#include "CoreAudioDevice.h"
+#include "Exception.h"
+
+AUD_NAMESPACE_BEGIN
+
+CoreAudioSynchronizer::CoreAudioSynchronizer(AudioUnit& audio_unit) :
+ m_clock_ref(nullptr),
+ m_playing(false)
+{
+ OSStatus status = CAClockNew(0, &m_clock_ref);
+
+ if(status != noErr)
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+
+ CAClockTimebase timebase = kCAClockTimebase_AudioOutputUnit;
+
+ status = CAClockSetProperty(m_clock_ref, kCAClockProperty_InternalTimebase, sizeof(timebase), &timebase);
+
+ if(status != noErr)
+ {
+ CAClockDispose(m_clock_ref);
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+ }
+
+ status = CAClockSetProperty(m_clock_ref, kCAClockProperty_TimebaseSource, sizeof(audio_unit), &audio_unit);
+
+ if(status != noErr)
+ {
+ CAClockDispose(m_clock_ref);
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+ }
+
+ CAClockSyncMode sync_mode = kCAClockSyncMode_Internal;
+
+ status = CAClockSetProperty(m_clock_ref, kCAClockProperty_SyncMode, sizeof(sync_mode), &sync_mode);
+
+ if(status != noErr)
+ {
+ CAClockDispose(m_clock_ref);
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+ }
+}
+
+CoreAudioSynchronizer::~CoreAudioSynchronizer()
+{
+ CAClockDispose(m_clock_ref);
+}
+
+void CoreAudioSynchronizer::seek(std::shared_ptr<IHandle> handle, double time)
+{
+ if(m_playing)
+ CAClockStop(m_clock_ref);
+
+ CAClockTime clock_time;
+ clock_time.format = kCAClockTimeFormat_Seconds;
+ clock_time.time.seconds = time;
+ CAClockSetCurrentTime(m_clock_ref, &clock_time);
+
+ handle->seek(time);
+
+ if(m_playing)
+ CAClockStart(m_clock_ref);
+}
+
+double CoreAudioSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
+{
+ CAClockTime clock_time;
+
+ OSStatus status;
+
+ if(m_playing)
+ status = CAClockGetCurrentTime(m_clock_ref, kCAClockTimeFormat_Seconds, &clock_time);
+ else
+ status = CAClockGetStartTime(m_clock_ref, kCAClockTimeFormat_Seconds, &clock_time);
+
+ if(status != noErr)
+ return 0;
+
+ return clock_time.time.seconds;
+}
+
+void CoreAudioSynchronizer::play()
+{
+ if(m_playing)
+ return;
+
+ m_playing = true;
+ CAClockStart(m_clock_ref);
+}
+
+void CoreAudioSynchronizer::stop()
+{
+ if(!m_playing)
+ return;
+
+ m_playing = false;
+ CAClockStop(m_clock_ref);
+}
+
+void CoreAudioSynchronizer::setSyncCallback(ISynchronizer::syncFunction function, void* data)
+{
+}
+
+int CoreAudioSynchronizer::isPlaying()
+{
+ return m_playing;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h
new file mode 100644
index 00000000000..4f9d9b28ea5
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef COREAUDIO_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file CoreAudioSynchronizer.h
+ * @ingroup plugin
+ * The CoreAudioSynchronizer class.
+ */
+
+#include "devices/ISynchronizer.h"
+
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/CoreAudioClock.h>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This class is a Synchronizer implementation using a CoreAudio clock.
+ */
+class AUD_PLUGIN_API CoreAudioSynchronizer : public ISynchronizer
+{
+private:
+ /// The CoreAudio clock referene.
+ CAClockRef m_clock_ref;
+
+ /// Whether the clock is currently playing.
+ bool m_playing;
+
+public:
+ /**
+ * Creates a new CoreAudioSynchronizer.
+ * @param device The device that should be synchronized.
+ */
+ CoreAudioSynchronizer(AudioUnit& audio_unit);
+ virtual ~CoreAudioSynchronizer();
+
+ virtual void seek(std::shared_ptr<IHandle> handle, double time);
+ virtual double getPosition(std::shared_ptr<IHandle> handle);
+ virtual void play();
+ virtual void stop();
+ virtual void setSyncCallback(syncFunction function, void* data);
+ virtual int isPlaying();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/jack/JackLibrary.h b/extern/audaspace/plugins/jack/JackLibrary.h
index 4e210852702..533eca7272a 100644
--- a/extern/audaspace/plugins/jack/JackLibrary.h
+++ b/extern/audaspace/plugins/jack/JackLibrary.h
@@ -21,9 +21,8 @@
#endif
/**
- * @file JackDevice.h
+ * @file JackLibrary.h
* @ingroup plugin
- * The JackDevice class.
*/
#include "Audaspace.h"
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
new file mode 100644
index 00000000000..0a50d5db2c7
--- /dev/null
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "PulseAudioDevice.h"
+#include "PulseAudioLibrary.h"
+#include "devices/DeviceManager.h"
+#include "devices/IDeviceFactory.h"
+#include "Exception.h"
+#include "IReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data)
+{
+ PulseAudioDevice* device = (PulseAudioDevice*)data;
+
+ device->m_state = AUD_pa_context_get_state(context);
+
+ AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
+}
+
+void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data)
+{
+ PulseAudioDevice* device = (PulseAudioDevice*)data;
+
+ void* buffer;
+
+ AUD_pa_stream_begin_write(stream, &buffer, &num_bytes);
+
+ device->mix((data_t*)buffer, num_bytes / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
+
+ AUD_pa_stream_write(stream, buffer, num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
+}
+
+void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
+{
+ PulseAudioDevice* device = (PulseAudioDevice*)data;
+
+ DeviceSpecs specs = device->getSpecs();
+
+ if(++device->m_underflows > 4 && device->m_buffersize < AUD_DEVICE_SAMPLE_SIZE(specs) * specs.rate * 2)
+ {
+ device->m_buffersize <<= 1;
+ device->m_underflows = 0;
+
+ pa_buffer_attr buffer_attr;
+
+ buffer_attr.fragsize = -1U;
+ buffer_attr.maxlength = -1U;
+ buffer_attr.minreq = -1U;
+ buffer_attr.prebuf = -1U;
+ buffer_attr.tlength = device->m_buffersize;
+
+ AUD_pa_stream_set_buffer_attr(stream, &buffer_attr, nullptr, nullptr);
+ }
+}
+
+void PulseAudioDevice::playing(bool playing)
+{
+ m_playback = playing;
+
+ AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
+}
+
+PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
+ m_playback(false),
+ m_state(PA_CONTEXT_UNCONNECTED),
+ m_buffersize(buffersize),
+ m_underflows(0)
+{
+ m_mainloop = AUD_pa_threaded_mainloop_new();
+
+ AUD_pa_threaded_mainloop_lock(m_mainloop);
+
+ m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
+
+ if(!m_context)
+ {
+ AUD_pa_threaded_mainloop_unlock(m_mainloop);
+ AUD_pa_threaded_mainloop_free(m_mainloop);
+
+ AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
+ }
+
+ AUD_pa_context_set_state_callback(m_context, PulseAudio_state_callback, this);
+
+ AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
+
+ AUD_pa_threaded_mainloop_start(m_mainloop);
+
+ while(m_state != PA_CONTEXT_READY)
+ {
+ switch(m_state)
+ {
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ AUD_pa_threaded_mainloop_unlock(m_mainloop);
+ AUD_pa_threaded_mainloop_stop(m_mainloop);
+
+ AUD_pa_context_disconnect(m_context);
+ AUD_pa_context_unref(m_context);
+
+ AUD_pa_threaded_mainloop_free(m_mainloop);
+
+ AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
+ break;
+ default:
+ AUD_pa_threaded_mainloop_wait(m_mainloop);
+ break;
+ }
+ }
+
+ if(specs.channels == CHANNELS_INVALID)
+ specs.channels = CHANNELS_STEREO;
+ if(specs.format == FORMAT_INVALID)
+ specs.format = FORMAT_FLOAT32;
+ if(specs.rate == RATE_INVALID)
+ specs.rate = RATE_48000;
+
+ m_specs = specs;
+
+ pa_sample_spec sample_spec;
+
+ sample_spec.channels = specs.channels;
+ sample_spec.format = PA_SAMPLE_FLOAT32;
+ sample_spec.rate = specs.rate;
+
+ switch(m_specs.format)
+ {
+ case FORMAT_U8:
+ sample_spec.format = PA_SAMPLE_U8;
+ break;
+ case FORMAT_S16:
+ sample_spec.format = PA_SAMPLE_S16NE;
+ break;
+ case FORMAT_S24:
+ sample_spec.format = PA_SAMPLE_S24NE;
+ break;
+ case FORMAT_S32:
+ sample_spec.format = PA_SAMPLE_S32NE;
+ break;
+ case FORMAT_FLOAT32:
+ sample_spec.format = PA_SAMPLE_FLOAT32;
+ break;
+ case FORMAT_FLOAT64:
+ m_specs.format = FORMAT_FLOAT32;
+ break;
+ default:
+ break;
+ }
+
+ m_stream = AUD_pa_stream_new(m_context, "Playback", &sample_spec, nullptr);
+
+ if(!m_stream)
+ {
+ AUD_pa_threaded_mainloop_unlock(m_mainloop);
+ AUD_pa_threaded_mainloop_stop(m_mainloop);
+
+ AUD_pa_context_disconnect(m_context);
+ AUD_pa_context_unref(m_context);
+
+ AUD_pa_threaded_mainloop_free(m_mainloop);
+
+ AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
+ }
+
+ AUD_pa_stream_set_write_callback(m_stream, PulseAudio_request, this);
+ AUD_pa_stream_set_underflow_callback(m_stream, PulseAudio_underflow, this);
+
+ pa_buffer_attr buffer_attr;
+
+ buffer_attr.fragsize = -1U;
+ buffer_attr.maxlength = -1U;
+ buffer_attr.minreq = -1U;
+ buffer_attr.prebuf = -1U;
+ buffer_attr.tlength = buffersize;
+
+ if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
+ {
+ AUD_pa_threaded_mainloop_unlock(m_mainloop);
+ AUD_pa_threaded_mainloop_stop(m_mainloop);
+
+ AUD_pa_context_disconnect(m_context);
+ AUD_pa_context_unref(m_context);
+
+ AUD_pa_threaded_mainloop_free(m_mainloop);
+
+ AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
+ }
+
+ AUD_pa_threaded_mainloop_unlock(m_mainloop);
+
+ create();
+}
+
+PulseAudioDevice::~PulseAudioDevice()
+{
+ AUD_pa_threaded_mainloop_stop(m_mainloop);
+
+ AUD_pa_context_disconnect(m_context);
+ AUD_pa_context_unref(m_context);
+
+ AUD_pa_threaded_mainloop_free(m_mainloop);
+
+ destroy();
+}
+
+class PulseAudioDeviceFactory : public IDeviceFactory
+{
+private:
+ DeviceSpecs m_specs;
+ int m_buffersize;
+ std::string m_name;
+
+public:
+ PulseAudioDeviceFactory() :
+ m_buffersize(AUD_DEFAULT_BUFFER_SIZE),
+ m_name("Audaspace")
+ {
+ m_specs.format = FORMAT_FLOAT32;
+ m_specs.channels = CHANNELS_STEREO;
+ m_specs.rate = RATE_48000;
+ }
+
+ virtual std::shared_ptr<IDevice> openDevice()
+ {
+ return std::shared_ptr<IDevice>(new PulseAudioDevice(m_name, m_specs, m_buffersize));
+ }
+
+ virtual int getPriority()
+ {
+ return 1 << 15;
+ }
+
+ virtual void setSpecs(DeviceSpecs specs)
+ {
+ m_specs = specs;
+ }
+
+ virtual void setBufferSize(int buffersize)
+ {
+ m_buffersize = buffersize;
+ }
+
+ virtual void setName(std::string name)
+ {
+ m_name = name;
+ }
+};
+
+void PulseAudioDevice::registerPlugin()
+{
+ if(loadPulseAudio())
+ DeviceManager::registerDevice("PulseAudio", std::shared_ptr<IDeviceFactory>(new PulseAudioDeviceFactory));
+}
+
+#ifdef PULSEAUDIO_PLUGIN
+extern "C" AUD_PLUGIN_API void registerPlugin()
+{
+ PulseAudioDevice::registerPlugin();
+}
+
+extern "C" AUD_PLUGIN_API const char* getName()
+{
+ return "PulseAudio";
+}
+#endif
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
new file mode 100644
index 00000000000..9efae5128b1
--- /dev/null
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef PULSEAUDIO_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file PulseAudioDevice.h
+ * @ingroup plugin
+ * The PulseAudioDevice class.
+ */
+
+#include "devices/SoftwareDevice.h"
+
+#include <pulse/pulseaudio.h>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This device plays back through PulseAudio, the simple direct media layer.
+ */
+class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
+{
+private:
+ /**
+ * Whether there is currently playback.
+ */
+ volatile bool m_playback;
+
+ pa_threaded_mainloop* m_mainloop;
+ pa_context* m_context;
+ pa_stream* m_stream;
+ pa_context_state_t m_state;
+
+ int m_buffersize;
+ uint32_t m_underflows;
+
+ /**
+ * Reports the state of the PulseAudio server connection.
+ * \param context The PulseAudio context.
+ * \param data The PulseAudio device.
+ */
+ AUD_LOCAL static void PulseAudio_state_callback(pa_context* context, void* data);
+
+ /**
+ * Supplies the next samples to PulseAudio.
+ * \param stream The PulseAudio stream.
+ * \param num_bytes The length in bytes to be supplied.
+ * \param data The PulseAudio device.
+ */
+ AUD_LOCAL static void PulseAudio_request(pa_stream* stream, size_t num_bytes, void* data);
+
+ /**
+ * Reports an underflow from the PulseAudio server.
+ * Automatically adjusts the latency if this happens too often.
+ * @param stream The PulseAudio stream.
+ * \param data The PulseAudio device.
+ */
+ AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
+
+ // delete copy constructor and operator=
+ PulseAudioDevice(const PulseAudioDevice&) = delete;
+ PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
+
+protected:
+ virtual void playing(bool playing);
+
+public:
+ /**
+ * Opens the PulseAudio audio device for playback.
+ * \param specs The wanted audio specification.
+ * \param buffersize The size of the internal buffer.
+ * \note The specification really used for opening the device may differ.
+ * \exception Exception Thrown if the audio device cannot be opened.
+ */
+ PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
+
+ /**
+ * Closes the PulseAudio audio device.
+ */
+ virtual ~PulseAudioDevice();
+
+ /**
+ * Registers this plugin.
+ */
+ static void registerPlugin();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.cpp b/extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.cpp
new file mode 100644
index 00000000000..66a0fae5ab6
--- /dev/null
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.cpp
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#define PULSEAUDIO_LIBRARY_IMPLEMENTATION
+
+#include <string>
+#include <array>
+
+#include "PulseAudioLibrary.h"
+
+#ifdef DYNLOAD_PULSEAUDIO
+#include "plugin/PluginManager.h"
+#endif
+
+AUD_NAMESPACE_BEGIN
+
+bool loadPulseAudio()
+{
+#ifdef DYNLOAD_PULSEAUDIO
+ std::array<const std::string, 2> names = {"libpulse.so", "libpulse.so.0"};
+
+ void* handle = nullptr;
+
+ for(auto& name : names)
+ {
+ handle = PluginManager::openLibrary(name);
+ if(handle)
+ break;
+ }
+
+ if (!handle)
+ return false;
+
+#define PULSEAUDIO_SYMBOL(sym) AUD_##sym = reinterpret_cast<decltype(&sym)>(PluginManager::lookupLibrary(handle, #sym))
+#else
+#define PULSEAUDIO_SYMBOL(sym) AUD_##sym = &sym
+#endif
+
+#include "PulseAudioSymbols.h"
+
+#undef PULSEAUDIO_SYMBOL
+
+ return AUD_pa_context_new != nullptr;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.h b/extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.h
new file mode 100644
index 00000000000..ae6c5951d11
--- /dev/null
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioLibrary.h
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef PULSEAUDIO_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file PulseAudioLibrary.h
+ * @ingroup plugin
+ */
+
+#include "Audaspace.h"
+
+#include <pulse/pulseaudio.h>
+
+AUD_NAMESPACE_BEGIN
+
+#ifdef PULSEAUDIO_LIBRARY_IMPLEMENTATION
+#define PULSEAUDIO_SYMBOL(sym) decltype(&sym) AUD_##sym
+#else
+#define PULSEAUDIO_SYMBOL(sym) extern decltype(&sym) AUD_##sym
+#endif
+
+#include "PulseAudioSymbols.h"
+
+#undef PULSEAUDIO_SYMBOL
+
+bool loadPulseAudio();
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
new file mode 100644
index 00000000000..9cefbc0c7e2
--- /dev/null
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+PULSEAUDIO_SYMBOL(pa_context_connect);
+PULSEAUDIO_SYMBOL(pa_context_disconnect);
+PULSEAUDIO_SYMBOL(pa_context_get_state);
+PULSEAUDIO_SYMBOL(pa_context_new);
+PULSEAUDIO_SYMBOL(pa_context_set_state_callback);
+PULSEAUDIO_SYMBOL(pa_context_unref);
+
+PULSEAUDIO_SYMBOL(pa_stream_begin_write);
+PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
+PULSEAUDIO_SYMBOL(pa_stream_cork);
+PULSEAUDIO_SYMBOL(pa_stream_new);
+PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
+PULSEAUDIO_SYMBOL(pa_stream_set_underflow_callback);
+PULSEAUDIO_SYMBOL(pa_stream_set_write_callback);
+PULSEAUDIO_SYMBOL(pa_stream_write);
+
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
+PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);
diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
new file mode 100644
index 00000000000..241f694feb5
--- /dev/null
+++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
@@ -0,0 +1,401 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "WASAPIDevice.h"
+#include "devices/DeviceManager.h"
+#include "devices/IDeviceFactory.h"
+#include "Exception.h"
+#include "IReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+template <class T> void SafeRelease(T **ppT)
+{
+ if(*ppT)
+ {
+ (*ppT)->Release();
+ *ppT = NULL;
+ }
+}
+
+void WASAPIDevice::start()
+{
+ lock();
+
+ if(!m_playing)
+ {
+ if(m_thread.joinable())
+ m_thread.join();
+
+ m_playing = true;
+
+ m_thread = std::thread(&WASAPIDevice::updateStream, this);
+ }
+
+ unlock();
+}
+
+void WASAPIDevice::updateStream()
+{
+ UINT32 buffer_size;
+ data_t* buffer;
+
+ if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
+ return;
+
+ IAudioRenderClient* render_client = nullptr;
+ const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
+
+ if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
+ return;
+
+ UINT32 padding;
+
+ if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
+ {
+ SafeRelease(&render_client);
+ return;
+ }
+
+ UINT32 length = buffer_size - padding;
+
+ if(FAILED(render_client->GetBuffer(length, &buffer)))
+ {
+ SafeRelease(&render_client);
+ return;
+ }
+
+ lock();
+
+ mix((data_t*)buffer, length);
+
+ unlock();
+
+ if(FAILED(render_client->ReleaseBuffer(length, 0)))
+ {
+ SafeRelease(&render_client);
+ return;
+ }
+
+ m_audio_client->Start();
+
+ auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
+
+ for(;;)
+ {
+ if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
+ {
+ m_audio_client->Stop();
+ SafeRelease(&render_client);
+ return;
+ }
+
+ length = buffer_size - padding;
+
+ if(FAILED(render_client->GetBuffer(length, &buffer)))
+ {
+ m_audio_client->Stop();
+ SafeRelease(&render_client);
+ return;
+ }
+
+ lock();
+
+ mix((data_t*)buffer, length);
+
+ unlock();
+
+ if(FAILED(render_client->ReleaseBuffer(length, 0)))
+ {
+ m_audio_client->Stop();
+ SafeRelease(&render_client);
+ return;
+ }
+
+ // stop thread
+ if(!m_playing)
+ {
+ m_audio_client->Stop();
+ SafeRelease(&render_client);
+ return;
+ }
+
+ std::this_thread::sleep_for(sleepDuration);
+ }
+}
+
+void WASAPIDevice::playing(bool playing)
+{
+ if(!m_playing && playing)
+ start();
+ else
+ m_playing = playing;
+}
+
+WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
+ m_playing(false),
+
+ m_imm_device_enumerator(nullptr),
+ m_imm_device(nullptr),
+ m_audio_client(nullptr),
+
+ m_wave_format_extensible({})
+{
+ // initialize COM if it hasn't happened yet
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+
+ const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
+ const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
+ const IID IID_IAudioClient = __uuidof(IAudioClient);
+
+ WAVEFORMATEXTENSIBLE wave_format_extensible_closest_match;
+ WAVEFORMATEXTENSIBLE* closest_match_pointer = &wave_format_extensible_closest_match;
+
+ HRESULT result;
+
+ REFERENCE_TIME minimum_time = 0;
+ REFERENCE_TIME buffer_duration;
+
+ if(FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, reinterpret_cast<void**>(&m_imm_device_enumerator))))
+ goto error;
+
+ if(FAILED(m_imm_device_enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &m_imm_device)))
+ goto error;
+
+ if(FAILED(m_imm_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&m_audio_client))))
+ goto error;
+
+ if(specs.channels == CHANNELS_INVALID)
+ specs.channels = CHANNELS_STEREO;
+ if(specs.format == FORMAT_INVALID)
+ specs.format = FORMAT_FLOAT32;
+ if(specs.rate == RATE_INVALID)
+ specs.rate = RATE_48000;
+
+ switch(specs.format)
+ {
+ case FORMAT_U8:
+ case FORMAT_S16:
+ case FORMAT_S24:
+ case FORMAT_S32:
+ m_wave_format_extensible.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ break;
+ case FORMAT_FLOAT32:
+ m_wave_format_extensible.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ break;
+ default:
+ m_wave_format_extensible.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ specs.format = FORMAT_FLOAT32;
+ break;
+ }
+
+ switch(specs.channels)
+ {
+ case CHANNELS_MONO:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_CENTER;
+ break;
+ case CHANNELS_STEREO:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
+ break;
+ case CHANNELS_STEREO_LFE:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY;
+ break;
+ case CHANNELS_SURROUND4:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
+ break;
+ case CHANNELS_SURROUND5:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
+ break;
+ case CHANNELS_SURROUND51:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
+ break;
+ case CHANNELS_SURROUND61:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
+ break;
+ case CHANNELS_SURROUND71:
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
+ break;
+ default:
+ specs.channels = CHANNELS_STEREO;
+ m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
+ break;
+ }
+
+ m_wave_format_extensible.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ m_wave_format_extensible.Format.nChannels = specs.channels;
+ m_wave_format_extensible.Format.nSamplesPerSec = specs.rate;
+ m_wave_format_extensible.Format.nAvgBytesPerSec = specs.rate * AUD_DEVICE_SAMPLE_SIZE(specs);
+ m_wave_format_extensible.Format.nBlockAlign = AUD_DEVICE_SAMPLE_SIZE(specs);
+ m_wave_format_extensible.Format.wBitsPerSample = AUD_FORMAT_SIZE(specs.format) * 8;
+ m_wave_format_extensible.Format.cbSize = 22;
+ m_wave_format_extensible.Samples.wValidBitsPerSample = m_wave_format_extensible.Format.wBitsPerSample;
+
+ result = m_audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, reinterpret_cast<const WAVEFORMATEX*>(&m_wave_format_extensible), reinterpret_cast<WAVEFORMATEX**>(&closest_match_pointer));
+
+ if(result == S_FALSE)
+ {
+ if(closest_match_pointer->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+ goto error;
+
+ specs.channels = Channels(closest_match_pointer->Format.nChannels);
+ specs.rate = closest_match_pointer->Format.nSamplesPerSec;
+
+ if(closest_match_pointer->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
+ {
+ if(closest_match_pointer->Format.wBitsPerSample == 32)
+ specs.format = FORMAT_FLOAT32;
+ else if(closest_match_pointer->Format.wBitsPerSample == 64)
+ specs.format = FORMAT_FLOAT64;
+ else
+ goto error;
+ }
+ else if(closest_match_pointer->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
+ {
+ switch(closest_match_pointer->Format.wBitsPerSample)
+ {
+ case 8:
+ specs.format = FORMAT_U8;
+ break;
+ case 16:
+ specs.format = FORMAT_S16;
+ break;
+ case 24:
+ specs.format = FORMAT_S24;
+ break;
+ case 32:
+ specs.format = FORMAT_S32;
+ break;
+ default:
+ goto error;
+ break;
+ }
+ }
+ else
+ goto error;
+
+ m_wave_format_extensible = *closest_match_pointer;
+
+ if(closest_match_pointer != &wave_format_extensible_closest_match)
+ {
+ CoTaskMemFree(closest_match_pointer);
+ closest_match_pointer = &wave_format_extensible_closest_match;
+ }
+ }
+ else if(FAILED(result))
+ goto error;
+
+ if(FAILED(m_audio_client->GetDevicePeriod(nullptr, &minimum_time)))
+ goto error;
+
+ buffer_duration = REFERENCE_TIME(buffersize) * REFERENCE_TIME(10000000) / REFERENCE_TIME(specs.rate);
+
+ if(minimum_time > buffer_duration)
+ buffer_duration = minimum_time;
+
+ m_specs = specs;
+
+ if(FAILED(m_audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, buffer_duration, 0, reinterpret_cast<WAVEFORMATEX*>(&m_wave_format_extensible), nullptr)))
+ goto error;
+
+ create();
+
+ return;
+
+ error:
+ if(closest_match_pointer != &wave_format_extensible_closest_match)
+ CoTaskMemFree(closest_match_pointer);
+ SafeRelease(&m_imm_device);
+ SafeRelease(&m_imm_device_enumerator);
+ SafeRelease(&m_audio_client);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with WASAPI.");
+}
+
+WASAPIDevice::~WASAPIDevice()
+{
+ lock();
+
+ stopAll();
+
+ unlock();
+
+ if(m_thread.joinable())
+ m_thread.join();
+
+ SafeRelease(&m_audio_client);
+ SafeRelease(&m_imm_device);
+ SafeRelease(&m_imm_device_enumerator);
+
+ destroy();
+}
+
+class WASAPIDeviceFactory : public IDeviceFactory
+{
+private:
+ DeviceSpecs m_specs;
+ int m_buffersize;
+
+public:
+ WASAPIDeviceFactory() :
+ m_buffersize(AUD_DEFAULT_BUFFER_SIZE)
+ {
+ m_specs.format = FORMAT_S16;
+ m_specs.channels = CHANNELS_STEREO;
+ m_specs.rate = RATE_48000;
+ }
+
+ virtual std::shared_ptr<IDevice> openDevice()
+ {
+ return std::shared_ptr<IDevice>(new WASAPIDevice(m_specs, m_buffersize));
+ }
+
+ virtual int getPriority()
+ {
+ return 1 << 15;
+ }
+
+ virtual void setSpecs(DeviceSpecs specs)
+ {
+ m_specs = specs;
+ }
+
+ virtual void setBufferSize(int buffersize)
+ {
+ m_buffersize = buffersize;
+ }
+
+ virtual void setName(std::string name)
+ {
+ }
+};
+
+void WASAPIDevice::registerPlugin()
+{
+ DeviceManager::registerDevice("WASAPI", std::shared_ptr<IDeviceFactory>(new WASAPIDeviceFactory));
+}
+
+#ifdef WASAPI_PLUGIN
+extern "C" AUD_PLUGIN_API void registerPlugin()
+{
+ WASAPIDevice::registerPlugin();
+}
+
+extern "C" AUD_PLUGIN_API const char* getName()
+{
+ return "WASAPI";
+}
+#endif
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.h b/extern/audaspace/plugins/wasapi/WASAPIDevice.h
new file mode 100644
index 00000000000..b7b520e802c
--- /dev/null
+++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.h
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef WASAPI_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file WASAPIDevice.h
+ * @ingroup plugin
+ * The WASAPIDevice class.
+ */
+
+#include "devices/SoftwareDevice.h"
+
+#include <thread>
+
+#include <windows.h>
+#include <audioclient.h>
+#include <mmdeviceapi.h>
+#include <mmreg.h>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This device plays back through WASAPI, the Windows audio API.
+ */
+class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice
+{
+private:
+ /**
+ * Whether there is currently playback.
+ */
+ bool m_playing;
+
+ IMMDeviceEnumerator* m_imm_device_enumerator;
+ IMMDevice* m_imm_device;
+ IAudioClient* m_audio_client;
+ WAVEFORMATEXTENSIBLE m_wave_format_extensible;
+
+ /**
+ * The streaming thread.
+ */
+ std::thread m_thread;
+
+ /**
+ * Starts the streaming thread.
+ */
+ AUD_LOCAL void start();
+
+ /**
+ * Streaming thread main function.
+ */
+ AUD_LOCAL void updateStream();
+
+ // delete copy constructor and operator=
+ WASAPIDevice(const WASAPIDevice&) = delete;
+ WASAPIDevice& operator=(const WASAPIDevice&) = delete;
+
+protected:
+ virtual void playing(bool playing);
+
+public:
+ /**
+ * Opens the WASAPI audio device for playback.
+ * \param specs The wanted audio specification.
+ * \param buffersize The size of the internal buffer.
+ * \note The specification really used for opening the device may differ.
+ * \exception Exception Thrown if the audio device cannot be opened.
+ */
+ WASAPIDevice(DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
+
+ /**
+ * Closes the WASAPI audio device.
+ */
+ virtual ~WASAPIDevice();
+
+ /**
+ * Registers this plugin.
+ */
+ static void registerPlugin();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/devices/NULLDevice.cpp b/extern/audaspace/src/devices/NULLDevice.cpp
index c3290465563..fa8e457dbd2 100644
--- a/extern/audaspace/src/devices/NULLDevice.cpp
+++ b/extern/audaspace/src/devices/NULLDevice.cpp
@@ -187,7 +187,7 @@ public:
void NULLDevice::registerPlugin()
{
- DeviceManager::registerDevice("Null", std::shared_ptr<IDeviceFactory>(new NULLDeviceFactory));
+ DeviceManager::registerDevice("None", std::shared_ptr<IDeviceFactory>(new NULLDeviceFactory));
}
AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in b/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in
index d08804bc2e7..3ab24986a0c 100644
--- a/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in
+++ b/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in
@@ -83,7 +83,12 @@ void PluginManager::loadPlugins(const std::string& path)
while(dirent* entry = readdir(dir))
{
const std::string filename = entry->d_name;
+
+#ifdef __APPLE__
+ const std::string end = ".dylib";
+#else
const std::string end = ".so";
+#endif
if(filename.length() >= end.length() && filename.substr(filename.length() - end.length()) == end)
{
diff --git a/extern/audaspace/src/plugin/PluginManagerWindows.cpp.in b/extern/audaspace/src/plugin/PluginManagerWindows.cpp.in
index 62350fd24fd..dd2df15751c 100644
--- a/extern/audaspace/src/plugin/PluginManagerWindows.cpp.in
+++ b/extern/audaspace/src/plugin/PluginManagerWindows.cpp.in
@@ -27,9 +27,9 @@ void* PluginManager::openLibrary(const std::string& path)
return reinterpret_cast<void*>(LoadLibrary(path.c_str()));
}
-void *PluginManager::lookupLibrary(void *handle, const std::string &name)
+void* PluginManager::lookupLibrary(void *handle, const std::string &name)
{
- return GetProcAddress(reinterpret_cast<HMODULE>(handle), name.c_str());
+ return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(handle), name.c_str()));
}
void PluginManager::closeLibrary(void *handle)
diff --git a/extern/mantaflow/CMakeLists.txt b/extern/mantaflow/CMakeLists.txt
index 3220a45bef4..9b047eb1a3e 100644
--- a/extern/mantaflow/CMakeLists.txt
+++ b/extern/mantaflow/CMakeLists.txt
@@ -32,9 +32,7 @@ if(MSVC_CLANG AND WITH_OPENMP AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.1
endif()
# Exporting functions from the blender binary gives linker warnings on Apple arm64 systems.
-# For now and until Apple arm64 is officially supported, these will just be silenced here.
-# TODO (sebbas): Check if official arm64 devices give linker warnings without this block.
-
+# Silence them here.
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
string(APPEND CMAKE_C_FLAGS " -fvisibility=hidden")
diff --git a/intern/clog/clog.c b/intern/clog/clog.c
index 2bc3985c71f..391b71d77de 100644
--- a/intern/clog/clog.c
+++ b/intern/clog/clog.c
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -38,8 +38,13 @@
#endif
#if defined(_MSC_VER)
+# include <Windows.h>
+
+# include <VersionHelpers.h> /* This needs to be included after Windows.h. */
# include <io.h>
-# include <windows.h>
+# if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+# endif
#endif
/* For printing timestamp. */
@@ -228,6 +233,9 @@ enum eCLogColor {
#define COLOR_LEN (COLOR_RESET + 1)
static const char *clg_color_table[COLOR_LEN] = {NULL};
+#ifdef _WIN32
+static DWORD clg_previous_console_mode = 0;
+#endif
static void clg_color_table_init(bool use_color)
{
@@ -295,19 +303,27 @@ static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
* - `foo` exact match of `foo`.
* - `foo.bar` exact match for `foo.bar`
* - `foo.*` match for `foo` & `foo.bar` & `foo.bar.baz`
+ * - `*bar*` match for `foo.bar` & `baz.bar` & `foo.barbaz`
* - `*` matches everything.
*/
static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
{
- const int identifier_len = strlen(identifier);
+ const size_t identifier_len = strlen(identifier);
for (uint i = 0; i < 2; i++) {
const CLG_IDFilter *flt = ctx->filters[i];
while (flt != NULL) {
- const int len = strlen(flt->match);
+ const size_t len = strlen(flt->match);
if (STREQ(flt->match, "*") || ((len == identifier_len) && (STREQ(identifier, flt->match)))) {
return (bool)i;
}
- if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) {
+ if (flt->match[0] == '*' && flt->match[len - 1] == '*') {
+ char *match = MEM_callocN(sizeof(char) * len - 1, __func__);
+ memcpy(match, flt->match + 1, len - 2);
+ if (strstr(identifier, match) != NULL) {
+ return (bool)i;
+ }
+ }
+ else if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) {
if (((identifier_len == len - 2) && STREQLEN(identifier, flt->match, len - 2)) ||
((identifier_len >= len - 1) && STREQLEN(identifier, flt->match, len - 1))) {
return (bool)i;
@@ -548,13 +564,22 @@ static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
#if defined(__unix__) || defined(__APPLE__)
ctx->use_color = isatty(ctx->output);
#elif defined(WIN32)
- /* Windows Terminal supports color like the Linux terminals do while the standard console does
- * not, the way to tell the two apart is to look at the `WT_SESSION` environment variable which
- * will only be defined for Windows Terminal. */
-
- /* #getenv is used here rather than #BLI_getenv since it would be a bad level call
- * and there are no benefits for using it in this context. */
- ctx->use_color = isatty(ctx->output) && getenv("WT_SESSION");
+ /* As of Windows 10 build 18298 all the standard consoles supports color
+ * like the Linux Terminal do, but it needs to be turned on.
+ * To turn on colors we need to enable virtual terminal processing by passing the flag
+ * ENABLE_VIRTUAL_TERMINAL_PROCESSING into SetConsoleMode.
+ * If the system doesn't support virtual terminal processing it will fail silently and the flag
+ * will not be set. */
+
+ GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &clg_previous_console_mode);
+
+ ctx->use_color = 0;
+ if (IsWindows10OrGreater() && isatty(ctx->output)) {
+ DWORD mode = clg_previous_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ if (SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), mode)) {
+ ctx->use_color = 1;
+ }
+ }
#endif
}
@@ -638,6 +663,9 @@ static CLogContext *CLG_ctx_init(void)
static void CLG_ctx_free(CLogContext *ctx)
{
+#if defined(WIN32)
+ SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), clg_previous_console_mode);
+#endif
while (ctx->types != NULL) {
CLG_LogType *item = ctx->types;
ctx->types = item->next;
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index a1ab5277744..72328333732 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -1234,7 +1234,8 @@ static void add_nodes(Scene *scene,
for (BL::NodeLink &b_link : b_ntree.links) {
/* Ignore invalid links to avoid unwanted cycles created in graph.
* Also ignore links with unavailable sockets. */
- if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled())) {
+ if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled()) ||
+ b_link.is_muted()) {
continue;
}
/* get blender link data */
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
index e094f339ede..d630e8965dc 100644
--- a/intern/cycles/bvh/bvh_optix.cpp
+++ b/intern/cycles/bvh/bvh_optix.cpp
@@ -27,8 +27,8 @@ BVHOptiX::BVHOptiX(const BVHParams &params_,
Device *device)
: BVH(params_, geometry_, objects_),
traversable_handle(0),
- as_data(device, params_.top_level ? "optix tlas" : "optix blas"),
- motion_transform_data(device, "optix motion transform")
+ as_data(device, params_.top_level ? "optix tlas" : "optix blas", false),
+ motion_transform_data(device, "optix motion transform", false)
{
}
diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp
index 44a51835f4c..5b62292ca55 100644
--- a/intern/cycles/device/cuda/device_cuda_impl.cpp
+++ b/intern/cycles/device/cuda/device_cuda_impl.cpp
@@ -854,7 +854,7 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
void *shared_pointer = 0;
- if (mem_alloc_result != CUDA_SUCCESS && can_map_host) {
+ if (mem_alloc_result != CUDA_SUCCESS && can_map_host && mem.type != MEM_DEVICE_ONLY) {
if (mem.shared_pointer) {
/* Another device already allocated host memory. */
mem_alloc_result = CUDA_SUCCESS;
@@ -877,8 +877,14 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
}
if (mem_alloc_result != CUDA_SUCCESS) {
- status = " failed, out of device and host memory";
- set_error("System is out of GPU and shared host memory");
+ if (mem.type == MEM_DEVICE_ONLY) {
+ status = " failed, out of device memory";
+ set_error("System is out of GPU memory");
+ }
+ else {
+ status = " failed, out of device and host memory";
+ set_error("System is out of GPU and shared host memory");
+ }
}
if (mem.name) {
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index fdfd3f83be6..e2f9c7391da 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -396,8 +396,7 @@ class CPUDevice : public Device {
<< string_human_readable_size(mem.memory_size()) << ")";
}
- if (mem.type == MEM_DEVICE_ONLY) {
- assert(!mem.host_pointer);
+ if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES;
void *data = util_aligned_malloc(mem.memory_size(), alignment);
mem.device_pointer = (device_ptr)data;
@@ -459,7 +458,7 @@ class CPUDevice : public Device {
tex_free((device_texture &)mem);
}
else if (mem.device_pointer) {
- if (mem.type == MEM_DEVICE_ONLY) {
+ if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
util_aligned_free((void *)mem.device_pointer);
}
mem.device_pointer = 0;
diff --git a/intern/cycles/device/device_denoising.h b/intern/cycles/device/device_denoising.h
index 2c0dc23b44a..bb8bdfdd225 100644
--- a/intern/cycles/device/device_denoising.h
+++ b/intern/cycles/device/device_denoising.h
@@ -171,7 +171,8 @@ class DenoisingTask {
bool gpu_temporary_mem;
DenoiseBuffers(Device *device)
- : mem(device, "denoising pixel buffer"), temporary_mem(device, "denoising temporary mem")
+ : mem(device, "denoising pixel buffer"),
+ temporary_mem(device, "denoising temporary mem", true)
{
}
} buffer;
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 1f63a152458..97459b9ae6a 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -270,8 +270,8 @@ class device_memory {
template<typename T> class device_only_memory : public device_memory {
public:
- device_only_memory(Device *device, const char *name)
- : device_memory(device, name, MEM_DEVICE_ONLY)
+ device_only_memory(Device *device, const char *name, bool allow_host_memory_fallback = false)
+ : device_memory(device, name, allow_host_memory_fallback ? MEM_READ_WRITE : MEM_DEVICE_ONLY)
{
data_type = device_type_traits<T>::data_type;
data_elements = max(device_type_traits<T>::num_elements, 1);
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index 07ce63f5394..51e1a0033ba 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -197,8 +197,8 @@ class OptiXDevice : public CUDADevice {
OptiXDevice(DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool background_)
: CUDADevice(info_, stats_, profiler_, background_),
sbt_data(this, "__sbt", MEM_READ_ONLY),
- launch_params(this, "__params"),
- denoiser_state(this, "__denoiser_state")
+ launch_params(this, "__params", false),
+ denoiser_state(this, "__denoiser_state", true)
{
// Store number of CUDA streams in device info
info.cpu_threads = DebugFlags().optix.cuda_streams;
@@ -878,8 +878,8 @@ class OptiXDevice : public CUDADevice {
device_ptr input_ptr = rtile.buffer + pixel_offset;
// Copy tile data into a common buffer if necessary
- device_only_memory<float> input(this, "denoiser input");
- device_vector<TileInfo> tile_info_mem(this, "denoiser tile info", MEM_READ_WRITE);
+ device_only_memory<float> input(this, "denoiser input", true);
+ device_vector<TileInfo> tile_info_mem(this, "denoiser tile info", MEM_READ_ONLY);
bool contiguous_memory = true;
for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
@@ -924,7 +924,7 @@ class OptiXDevice : public CUDADevice {
}
# if OPTIX_DENOISER_NO_PIXEL_STRIDE
- device_only_memory<float> input_rgb(this, "denoiser input rgb");
+ device_only_memory<float> input_rgb(this, "denoiser input rgb", true);
input_rgb.alloc_to_device(rect_size.x * rect_size.y * 3 * task.denoising.input_passes);
void *input_args[] = {&input_rgb.device_pointer,
@@ -1146,6 +1146,13 @@ class OptiXDevice : public CUDADevice {
const OptixBuildInput &build_input,
uint16_t num_motion_steps)
{
+ /* Allocate and build acceleration structures only one at a time, to prevent parallel builds
+ * from running out of memory (since both original and compacted acceleration structure memory
+ * may be allocated at the same time for the duration of this function). The builds would
+ * otherwise happen on the same CUDA stream anyway. */
+ static thread_mutex mutex;
+ thread_scoped_lock lock(mutex);
+
const CUDAContextScope scope(cuContext);
// Compute memory usage
@@ -1170,11 +1177,12 @@ class OptiXDevice : public CUDADevice {
optixAccelComputeMemoryUsage(context, &options, &build_input, 1, &sizes));
// Allocate required output buffers
- device_only_memory<char> temp_mem(this, "optix temp as build mem");
+ device_only_memory<char> temp_mem(this, "optix temp as build mem", true);
temp_mem.alloc_to_device(align_up(sizes.tempSizeInBytes, 8) + 8);
if (!temp_mem.device_pointer)
return false; // Make sure temporary memory allocation succeeded
+ // Acceleration structure memory has to be allocated on the device (not allowed to be on host)
device_only_memory<char> &out_data = bvh->as_data;
if (operation == OPTIX_BUILD_OPERATION_BUILD) {
assert(out_data.device == this);
@@ -1222,7 +1230,7 @@ class OptiXDevice : public CUDADevice {
// There is no point compacting if the size does not change
if (compacted_size < sizes.outputSizeInBytes) {
- device_only_memory<char> compacted_data(this, "optix compacted as");
+ device_only_memory<char> compacted_data(this, "optix compacted as", false);
compacted_data.alloc_to_device(compacted_size);
if (!compacted_data.device_pointer)
// Do not compact if memory allocation for compacted acceleration structure fails
@@ -1242,6 +1250,7 @@ class OptiXDevice : public CUDADevice {
std::swap(out_data.device_size, compacted_data.device_size);
std::swap(out_data.device_pointer, compacted_data.device_pointer);
+ // Original acceleration structure memory is freed when 'compacted_data' goes out of scope
}
}
diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp
index 2cc9c6a985f..55fbaa31e42 100644
--- a/intern/cycles/device/device_task.cpp
+++ b/intern/cycles/device/device_task.cpp
@@ -45,7 +45,16 @@ DeviceTask::DeviceTask(Type type_)
shader_filter(0),
shader_x(0),
shader_w(0),
- buffers(nullptr)
+ buffers(nullptr),
+ tile_types(0),
+ denoising_from_render(false),
+ pass_stride(0),
+ frame_stride(0),
+ target_pass_stride(0),
+ pass_denoising_data(0),
+ pass_denoising_clean(0),
+ need_finish_queue(false),
+ integrator_branched(false)
{
last_update_time = time_dt();
}
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
index d1eadf21b1b..4efbd6725ee 100644
--- a/intern/cycles/graph/node_type.cpp
+++ b/intern/cycles/graph/node_type.cpp
@@ -154,7 +154,7 @@ void NodeType::register_input(ustring name,
int struct_offset,
const void *default_value,
const NodeEnum *enum_values,
- const NodeType **node_type,
+ const NodeType *node_type,
int flags,
int extra_flags)
{
diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h
index 3b9b3007099..2a741d9b06f 100644
--- a/intern/cycles/graph/node_type.h
+++ b/intern/cycles/graph/node_type.h
@@ -87,7 +87,7 @@ struct SocketType {
int struct_offset;
const void *default_value;
const NodeEnum *enum_values;
- const NodeType **node_type;
+ const NodeType *node_type;
int flags;
ustring ui_name;
SocketModifiedFlags modified_flag_bit;
@@ -115,7 +115,7 @@ struct NodeType {
int struct_offset,
const void *default_value,
const NodeEnum *enum_values = NULL,
- const NodeType **node_type = NULL,
+ const NodeType *node_type = NULL,
int flags = 0,
int extra_flags = 0);
void register_output(ustring name, ustring ui_name, SocketType::Type type);
@@ -140,27 +140,38 @@ struct NodeType {
static unordered_map<ustring, NodeType, ustringHash> &types();
};
-/* Node Definition Macros */
+/* Node Definition Macros
+ *
+ * Node we use accessor to get node types to ensure correct static
+ * initialization order. */
#define NODE_DECLARE \
+ static const NodeType *get_node_type(); \
template<typename T> static const NodeType *register_type(); \
- static Node *create(const NodeType *type); \
- static const NodeType *node_type;
+ static Node *create(const NodeType *type);
#define NODE_DEFINE(structname) \
- const NodeType *structname::node_type = structname::register_type<structname>(); \
Node *structname::create(const NodeType *) \
{ \
return new structname(); \
} \
+ const NodeType *structname::get_node_type() \
+ { \
+ static const NodeType *node_type = register_type<structname>(); \
+ return node_type; \
+ } \
template<typename T> const NodeType *structname::register_type()
#define NODE_ABSTRACT_DECLARE \
template<typename T> static const NodeType *register_base_type(); \
- static const NodeType *node_base_type;
+ static const NodeType *get_node_base_type();
#define NODE_ABSTRACT_DEFINE(structname) \
- const NodeType *structname::node_base_type = structname::register_base_type<structname>(); \
+ const NodeType *structname::get_node_base_type() \
+ { \
+ static const NodeType *node_base_type = register_base_type<structname>(); \
+ return node_base_type; \
+ } \
template<typename T> const NodeType *structname::register_base_type()
/* Sock Definition Macros */
diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
index d333400cc4a..43462662b6a 100644
--- a/intern/cycles/graph/node_xml.cpp
+++ b/intern/cycles/graph/node_xml.cpp
@@ -200,7 +200,7 @@ void xml_read_node(XMLReader &reader, Node *node, xml_node xml_node)
map<ustring, Node *>::iterator it = reader.node_map.find(value);
if (it != reader.node_map.end()) {
Node *value_node = it->second;
- if (value_node->is_a(*(socket.node_type)))
+ if (value_node->is_a(socket.node_type))
node->set(socket, it->second);
}
break;
@@ -215,7 +215,7 @@ void xml_read_node(XMLReader &reader, Node *node, xml_node xml_node)
map<ustring, Node *>::iterator it = reader.node_map.find(ustring(tokens[i]));
if (it != reader.node_map.end()) {
Node *value_node = it->second;
- value[i] = (value_node->is_a(*(socket.node_type))) ? value_node : NULL;
+ value[i] = (value_node->is_a(socket.node_type)) ? value_node : NULL;
}
else {
value[i] = NULL;
diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h
index ce37bd0b15e..ba25c0e24e4 100644
--- a/intern/cycles/kernel/kernel_montecarlo.h
+++ b/intern/cycles/kernel/kernel_montecarlo.h
@@ -195,108 +195,31 @@ ccl_device float2 regular_polygon_sample(float corners, float rotation, float u,
ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
{
- float3 R = 2 * dot(N, I) * N - I;
-
- /* Reflection rays may always be at least as shallow as the incoming ray. */
- float threshold = min(0.9f * dot(Ng, I), 0.01f);
- if (dot(Ng, R) >= threshold) {
- return N;
- }
-
- /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
- * The X axis is found by normalizing the component of N that's orthogonal to Ng.
- * The Y axis isn't actually needed.
- */
- float NdotNg = dot(N, Ng);
- float3 X = normalize(N - NdotNg * Ng);
-
- /* Keep math expressions. */
- /* clang-format off */
- /* Calculate N.z and N.x in the local coordinate system.
- *
- * The goal of this computation is to find a N' that is rotated towards Ng just enough
- * to lift R' above the threshold (here called t), therefore dot(R', Ng) = t.
- *
- * According to the standard reflection equation,
- * this means that we want dot(2*dot(N', I)*N' - I, Ng) = t.
- *
- * Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get
- * 2*dot(N', I)*N'.z - I.z = t.
- *
- * The rotation is simple to express in the coordinate system we formed -
- * since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane,
- * so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z .
- *
- * Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2).
- *
- * With these simplifications,
- * we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t.
- *
- * The only unknown here is N'.z, so we can solve for that.
- *
- * The equation has four solutions in general:
- *
- * N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2))
- * We can simplify this expression a bit by grouping terms:
- *
- * a = I.x^2 + I.z^2
- * b = sqrt(I.x^2 * (a - t^2))
- * c = I.z*t + a
- * N'.z = +-sqrt(0.5*(+-b + c)/a)
- *
- * Two solutions can immediately be discarded because they're negative so N' would lie in the
- * lower hemisphere.
- */
- /* clang-format on */
-
- float Ix = dot(I, X), Iz = dot(I, Ng);
- float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
- float a = Ix2 + Iz2;
-
- float b = safe_sqrtf(Ix2 * (a - sqr(threshold)));
- float c = Iz * threshold + a;
-
- /* Evaluate both solutions.
- * In many cases one can be immediately discarded (if N'.z would be imaginary or larger than
- * one), so check for that first. If no option is viable (might happen in extreme cases like N
- * being in the wrong hemisphere), give up and return Ng. */
- float fac = 0.5f / a;
- float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c);
- bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f));
- bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f));
-
- float2 N_new;
- if (valid1 && valid2) {
- /* If both are possible, do the expensive reflection-based check. */
- float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2));
- float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2));
-
- float R1 = 2 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz;
- float R2 = 2 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz;
-
- valid1 = (R1 >= 1e-5f);
- valid2 = (R2 >= 1e-5f);
- if (valid1 && valid2) {
- /* If both solutions are valid, return the one with the shallower reflection since it will be
- * closer to the input (if the original reflection wasn't shallow, we would not be in this
- * part of the function). */
- N_new = (R1 < R2) ? N1 : N2;
+ float3 R;
+ float NI = dot(N, I);
+ float NgR, threshold;
+
+ /* Check if the incident ray is coming from behind normal N. */
+ if (NI > 0) {
+ /* Normal reflection */
+ R = (2 * NI) * N - I;
+ NgR = dot(Ng, R);
+
+ /* Reflection rays may always be at least as shallow as the incoming ray. */
+ threshold = min(0.9f * dot(Ng, I), 0.01f);
+ if (NgR >= threshold) {
+ return N;
}
- else {
- /* If only one reflection is valid (= positive), pick that one. */
- N_new = (R1 > R2) ? N1 : N2;
- }
- }
- else if (valid1 || valid2) {
- /* Only one solution passes the N'.z criterium, so pick that one. */
- float Nz2 = valid1 ? N1_z2 : N2_z2;
- N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2));
}
else {
- return Ng;
+ /* Bad incident */
+ R = -I;
+ NgR = dot(Ng, R);
+ threshold = 0.01f;
}
- return N_new.x * X + N_new.y * Ng;
+ R = R + Ng * (threshold - NgR); /* Lift the reflection above the threshold. */
+ return normalize(I * len(R) + R * len(I)); /* Find a bisector. */
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index e46b0436107..22a89997683 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -175,7 +175,8 @@ ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg,
const float object_step_size,
float t,
float *step_size,
- float *step_offset)
+ float *step_shade_offset,
+ float *steps_offset)
{
const int max_steps = kernel_data.integrator.volume_max_steps;
float step = min(object_step_size, t);
@@ -186,7 +187,14 @@ ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg,
}
*step_size = step;
- *step_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4) * step;
+
+ /* Perform shading at this offset within a step, to integrate over
+ * over the entire step segment. */
+ *step_shade_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4);
+
+ /* Shift starting point of all segment by this random amount to avoid
+ * banding artifacts from the volume bounding shape. */
+ *steps_offset = path_state_rng_1D_hash(kg, state, 0x3d22c7b3);
}
/* Volume Shadows
@@ -220,10 +228,15 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
float3 tp = *throughput;
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
- /* prepare for stepping */
+ /* Prepare for stepping.
+ * For shadows we do not offset all segments, since the starting point is
+ * already a random distance inside the volume. It also appears to create
+ * banding artifacts for unknown reasons. */
int max_steps = kernel_data.integrator.volume_max_steps;
- float step_offset, step_size;
- kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset);
+ float step_size, step_shade_offset, unused;
+ kernel_volume_step_init(
+ kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &unused);
+ const float steps_offset = 1.0f;
/* compute extinction at the start */
float t = 0.0f;
@@ -232,23 +245,17 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
for (int i = 0; i < max_steps; i++) {
/* advance to new position */
- float new_t = min(ray->t, (i + 1) * step_size);
-
- /* use random position inside this segment to sample shader, adjust
- * for last step that is shorter than other steps. */
- if (new_t == ray->t) {
- step_offset *= (new_t - t) / step_size;
- }
+ float new_t = min(ray->t, (i + steps_offset) * step_size);
+ float dt = new_t - t;
- float3 new_P = ray->P + ray->D * (t + step_offset);
+ float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
float3 sigma_t = zero_float3();
/* compute attenuation over segment */
if (volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) {
/* Compute expf() only for every Nth step, to save some calculations
* because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */
-
- sum += (-sigma_t * (new_t - t));
+ sum += (-sigma_t * dt);
if ((i & 0x07) == 0) { /* ToDo: Other interval? */
tp = *throughput * exp3(sum);
@@ -567,10 +574,12 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
float3 tp = *throughput;
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
- /* prepare for stepping */
+ /* Prepare for stepping.
+ * Using a different step offset for the first step avoids banding artifacts. */
int max_steps = kernel_data.integrator.volume_max_steps;
- float step_offset, step_size;
- kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset);
+ float step_size, step_shade_offset, steps_offset;
+ kernel_volume_step_init(
+ kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &steps_offset);
/* compute coefficients at the start */
float t = 0.0f;
@@ -584,16 +593,10 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
for (int i = 0; i < max_steps; i++) {
/* advance to new position */
- float new_t = min(ray->t, (i + 1) * step_size);
+ float new_t = min(ray->t, (i + steps_offset) * step_size);
float dt = new_t - t;
- /* use random position inside this segment to sample shader,
- * for last shorter step we remap it to fit within the segment. */
- if (new_t == ray->t) {
- step_offset *= (new_t - t) / step_size;
- }
-
- float3 new_P = ray->P + ray->D * (t + step_offset);
+ float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
VolumeShaderCoefficients coeff ccl_optional_struct_init;
/* compute segment */
@@ -771,11 +774,12 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
/* prepare for volume stepping */
int max_steps;
- float step_size, step_offset;
+ float step_size, step_shade_offset, steps_offset;
if (object_step_size != FLT_MAX) {
max_steps = kernel_data.integrator.volume_max_steps;
- kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset);
+ kernel_volume_step_init(
+ kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &steps_offset);
# ifdef __KERNEL_CPU__
/* NOTE: For the branched path tracing it's possible to have direct
@@ -802,7 +806,8 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
else {
max_steps = 1;
step_size = ray->t;
- step_offset = 0.0f;
+ step_shade_offset = 0.0f;
+ steps_offset = 1.0f;
segment->steps = &segment->stack_step;
}
@@ -821,16 +826,10 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
for (int i = 0; i < max_steps; i++, step++) {
/* advance to new position */
- float new_t = min(ray->t, (i + 1) * step_size);
+ float new_t = min(ray->t, (i + steps_offset) * step_size);
float dt = new_t - t;
- /* use random position inside this segment to sample shader,
- * for last shorter step we remap it to fit within the segment. */
- if (new_t == ray->t) {
- step_offset *= (new_t - t) / step_size;
- }
-
- float3 new_P = ray->P + ray->D * (t + step_offset);
+ float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
VolumeShaderCoefficients coeff ccl_optional_struct_init;
/* compute segment */
@@ -888,7 +887,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
step->accum_transmittance = accum_transmittance;
step->cdf_distance = cdf_distance;
step->t = new_t;
- step->shade_t = t + step_offset;
+ step->shade_t = t + dt * step_shade_offset;
/* stop if at the end of the volume */
t = new_t;
diff --git a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h
index 82ad9225fc3..132653fa7ca 100644
--- a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h
+++ b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h
@@ -68,8 +68,8 @@ ccl_device T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, f
x = (x * info.width) - 0.5f;
y = (y * info.height) - 0.5f;
- float px = floor(x);
- float py = floor(y);
+ float px = floorf(x);
+ float py = floorf(y);
float fx = x - px;
float fy = y - py;
@@ -95,9 +95,9 @@ ccl_device T kernel_tex_image_interp_tricubic(const TextureInfo &info, float x,
y = (y * info.height) - 0.5f;
z = (z * info.depth) - 0.5f;
- float px = floor(x);
- float py = floor(y);
- float pz = floor(z);
+ float px = floorf(x);
+ float py = floorf(y);
+ float pz = floorf(z);
float fx = x - px;
float fy = y - py;
float fz = z - pz;
@@ -127,9 +127,9 @@ ccl_device T kernel_tex_image_interp_tricubic(const TextureInfo &info, float x,
template<typename T, typename S>
ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, float z)
{
- float px = floor(x);
- float py = floor(y);
- float pz = floor(z);
+ float px = floorf(x);
+ float py = floorf(y);
+ float pz = floorf(z);
float fx = x - px;
float fy = y - py;
float fz = z - pz;
diff --git a/intern/cycles/kernel/shaders/node_attribute.osl b/intern/cycles/kernel/shaders/node_attribute.osl
index 205d0a21bed..b7f35956ec7 100644
--- a/intern/cycles/kernel/shaders/node_attribute.osl
+++ b/intern/cycles/kernel/shaders/node_attribute.osl
@@ -23,7 +23,7 @@ shader node_attribute(string bump_offset = "center",
output float Fac = 0.0,
output float Alpha = 0.0)
{
- float data[4];
+ float data[4] = {0.0, 0.0, 0.0, 0.0};
getattribute(name, data);
Color = color(data[0], data[1], data[2]);
Vector = point(Color);
diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/shaders/node_light_path.osl
index 4ff06915771..ba268db288c 100644
--- a/intern/cycles/kernel/shaders/node_light_path.osl
+++ b/intern/cycles/kernel/shaders/node_light_path.osl
@@ -42,23 +42,23 @@ shader node_light_path(output float IsCameraRay = 0.0,
getattribute("path:ray_length", RayLength);
- int ray_depth;
+ int ray_depth = 0;
getattribute("path:ray_depth", ray_depth);
RayDepth = (float)ray_depth;
- int diffuse_depth;
+ int diffuse_depth = 0;
getattribute("path:diffuse_depth", diffuse_depth);
DiffuseDepth = (float)diffuse_depth;
- int glossy_depth;
+ int glossy_depth = 0;
getattribute("path:glossy_depth", glossy_depth);
GlossyDepth = (float)glossy_depth;
- int transparent_depth;
+ int transparent_depth = 0;
getattribute("path:transparent_depth", transparent_depth);
TransparentDepth = (float)transparent_depth;
- int transmission_depth;
+ int transmission_depth = 0;
getattribute("path:transmission_depth", transmission_depth);
TransmissionDepth = (float)transmission_depth;
}
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
index 912960f13ab..6d4780f6dae 100644
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ b/intern/cycles/kernel/shaders/node_normal_map.osl
@@ -31,7 +31,7 @@ shader node_normal_map(normal NormalIn = N,
vector tangent;
vector ninterp;
float tangent_sign;
- float is_smooth;
+ float is_smooth = 0.0;
getattribute("geom:is_smooth", is_smooth);
if (!is_smooth) {
diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/shaders/node_tangent.osl
index 83f19a4610b..f086fa079ec 100644
--- a/intern/cycles/kernel/shaders/node_tangent.osl
+++ b/intern/cycles/kernel/shaders/node_tangent.osl
@@ -22,7 +22,7 @@ shader node_tangent(normal NormalIn = N,
string axis = "z",
output normal Tangent = normalize(dPdu))
{
- vector T;
+ vector T = vector(0.0, 0.0, 0.0);
if (direction_type == "uv_map") {
getattribute(attr_name, T);
diff --git a/intern/cycles/kernel/shaders/stdcycles.h b/intern/cycles/kernel/shaders/stdcycles.h
index dd604da68ce..af7b645d9a2 100644
--- a/intern/cycles/kernel/shaders/stdcycles.h
+++ b/intern/cycles/kernel/shaders/stdcycles.h
@@ -84,67 +84,30 @@ closure color principled_hair(normal N,
closure color henyey_greenstein(float g) BUILTIN;
closure color absorption() BUILTIN;
-normal ensure_valid_reflection(normal Ng, vector I, normal N)
+normal ensure_valid_reflection(normal Ng, normal I, normal N)
{
/* The implementation here mirrors the one in kernel_montecarlo.h,
* check there for an explanation of the algorithm. */
-
- float sqr(float x)
- {
- return x * x;
- }
-
- vector R = 2 * dot(N, I) * N - I;
-
- float threshold = min(0.9 * dot(Ng, I), 0.01);
- if (dot(Ng, R) >= threshold) {
- return N;
- }
-
- float NdotNg = dot(N, Ng);
- vector X = normalize(N - NdotNg * Ng);
-
- float Ix = dot(I, X), Iz = dot(I, Ng);
- float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
- float a = Ix2 + Iz2;
-
- float b = sqrt(Ix2 * (a - sqr(threshold)));
- float c = Iz * threshold + a;
-
- float fac = 0.5 / a;
- float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c);
- int valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5));
- int valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5));
-
- float N_new_x, N_new_z;
- if (valid1 && valid2) {
- float N1_x = sqrt(1.0 - N1_z2), N1_z = sqrt(N1_z2);
- float N2_x = sqrt(1.0 - N2_z2), N2_z = sqrt(N2_z2);
-
- float R1 = 2 * (N1_x * Ix + N1_z * Iz) * N1_z - Iz;
- float R2 = 2 * (N2_x * Ix + N2_z * Iz) * N2_z - Iz;
-
- valid1 = (R1 >= 1e-5);
- valid2 = (R2 >= 1e-5);
- if (valid1 && valid2) {
- N_new_x = (R1 < R2) ? N1_x : N2_x;
- N_new_z = (R1 < R2) ? N1_z : N2_z;
- }
- else {
- N_new_x = (R1 > R2) ? N1_x : N2_x;
- N_new_z = (R1 > R2) ? N1_z : N2_z;
+ vector R;
+ float NI = dot(N, I);
+ float NgR, threshold;
+
+ if (NI > 0) {
+ R = (2 * NI) * N - I;
+ NgR = dot(Ng, R);
+ threshold = min(0.9 * dot(Ng, I), 0.01);
+ if (NgR >= threshold) {
+ return N;
}
}
- else if (valid1 || valid2) {
- float Nz2 = valid1 ? N1_z2 : N2_z2;
- N_new_x = sqrt(1.0 - Nz2);
- N_new_z = sqrt(Nz2);
- }
else {
- return Ng;
+ R = -I;
+ NgR = dot(Ng, R);
+ threshold = 0.01;
}
- return N_new_x * X + N_new_z * Ng;
+ R = R + Ng * (threshold - NgR);
+ return normalize(I * length(R) + R * length(I));
}
#endif /* CCL_STDOSL_H */
diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp
index 627ffe2318a..e4f0690c401 100644
--- a/intern/cycles/render/alembic.cpp
+++ b/intern/cycles/render/alembic.cpp
@@ -402,16 +402,16 @@ static void add_uvs(AlembicProcedural *proc,
}
const ISampleSelector iss = ISampleSelector(time);
- const IV2fGeomParam::Sample sample = uvs.getExpandedValue(iss);
-
const IV2fGeomParam::Sample uvsample = uvs.getIndexedValue(iss);
if (!uvsample.valid()) {
continue;
}
- const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
- const array<int3> *triangles_loops = cached_data.triangles_loops.data_for_time_no_check(time);
+ const array<int3> *triangles =
+ cached_data.triangles.data_for_time_no_check(time).get_data_or_null();
+ const array<int3> *triangles_loops =
+ cached_data.triangles_loops.data_for_time_no_check(time).get_data_or_null();
if (!triangles || !triangles_loops) {
continue;
@@ -458,7 +458,8 @@ static void add_normals(const Int32ArraySamplePtr face_indices,
*normals.getTimeSampling());
attr.std = ATTR_STD_VERTEX_NORMAL;
- const array<float3> *vertices = cached_data.vertices.data_for_time_no_check(time);
+ const array<float3> *vertices =
+ cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
if (!vertices) {
return;
@@ -493,7 +494,8 @@ static void add_normals(const Int32ArraySamplePtr face_indices,
*normals.getTimeSampling());
attr.std = ATTR_STD_VERTEX_NORMAL;
- const array<float3> *vertices = cached_data.vertices.data_for_time_no_check(time);
+ const array<float3> *vertices =
+ cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
if (!vertices) {
return;
@@ -597,7 +599,7 @@ NODE_DEFINE(AlembicObject)
NodeType *type = NodeType::add("alembic_object", create);
SOCKET_STRING(path, "Alembic Path", ustring());
- SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", &Shader::node_type);
+ SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type());
SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f);
@@ -607,7 +609,7 @@ NODE_DEFINE(AlembicObject)
return type;
}
-AlembicObject::AlembicObject() : Node(node_type)
+AlembicObject::AlembicObject() : Node(get_node_type())
{
schema_type = INVALID;
}
@@ -717,11 +719,15 @@ void AlembicObject::read_face_sets(SchemaType &schema,
void AlembicObject::load_all_data(AlembicProcedural *proc,
IPolyMeshSchema &schema,
- float scale,
Progress &progress)
{
cached_data.clear();
+ /* Only load data for the original Geometry. */
+ if (instance_of) {
+ return;
+ }
+
const TimeSamplingPtr time_sampling = schema.getTimeSampling();
cached_data.set_time_sampling(*time_sampling);
@@ -780,22 +786,18 @@ void AlembicObject::load_all_data(AlembicProcedural *proc,
add_uvs(proc, uvs, cached_data, progress);
}
- if (progress.get_cancel()) {
- return;
- }
-
- setup_transform_cache(scale);
-
data_loaded = true;
}
-void AlembicObject::load_all_data(AlembicProcedural *proc,
- ISubDSchema &schema,
- float scale,
- Progress &progress)
+void AlembicObject::load_all_data(AlembicProcedural *proc, ISubDSchema &schema, Progress &progress)
{
cached_data.clear();
+ /* Only load data for the original Geometry. */
+ if (instance_of) {
+ return;
+ }
+
AttributeRequestSet requested_attributes = get_requested_attributes();
const TimeSamplingPtr time_sampling = schema.getTimeSampling();
@@ -920,19 +922,21 @@ void AlembicObject::load_all_data(AlembicProcedural *proc,
return;
}
- setup_transform_cache(scale);
-
data_loaded = true;
}
void AlembicObject::load_all_data(AlembicProcedural *proc,
const ICurvesSchema &schema,
- float scale,
Progress &progress,
float default_radius)
{
cached_data.clear();
+ /* Only load data for the original Geometry. */
+ if (instance_of) {
+ return;
+ }
+
const TimeSamplingPtr time_sampling = schema.getTimeSampling();
cached_data.set_time_sampling(*time_sampling);
@@ -1007,8 +1011,6 @@ void AlembicObject::load_all_data(AlembicProcedural *proc,
// TODO(@kevindietrich): attributes, need example files
- setup_transform_cache(scale);
-
data_loaded = true;
}
@@ -1017,6 +1019,14 @@ void AlembicObject::setup_transform_cache(float scale)
cached_data.transforms.clear();
cached_data.transforms.invalidate_last_loaded_time();
+ if (scale == 0.0f) {
+ scale = 1.0f;
+ }
+
+ if (xform_time_sampling) {
+ cached_data.transforms.set_time_sampling(*xform_time_sampling);
+ }
+
if (xform_samples.size() == 0) {
Transform tfm = transform_scale(make_float3(scale));
cached_data.transforms.add_data(tfm, 0.0);
@@ -1103,9 +1113,10 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params,
attribute.element = ATTR_ELEMENT_CORNER;
attribute.type_desc = TypeFloat2;
- const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
- const array<int3> *triangles_loops = cached_data.triangles_loops.data_for_time_no_check(
- time);
+ const array<int3> *triangles =
+ cached_data.triangles.data_for_time_no_check(time).get_data_or_null();
+ const array<int3> *triangles_loops =
+ cached_data.triangles_loops.data_for_time_no_check(time).get_data_or_null();
if (!triangles || !triangles_loops) {
return;
@@ -1158,7 +1169,8 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params,
attribute.element = ATTR_ELEMENT_CORNER_BYTE;
attribute.type_desc = TypeRGBA;
- const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
+ const array<int3> *triangles =
+ cached_data.triangles.data_for_time_no_check(time).get_data_or_null();
if (!triangles) {
return;
@@ -1214,7 +1226,8 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params,
attribute.element = ATTR_ELEMENT_CORNER_BYTE;
attribute.type_desc = TypeRGBA;
- const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
+ const array<int3> *triangles =
+ cached_data.triangles.data_for_time_no_check(time).get_data_or_null();
if (!triangles) {
return;
@@ -1253,7 +1266,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data,
set<Attribute *> cached_attributes;
for (CachedData::CachedAttribute &attribute : cached_data.attributes) {
- const array<char> *attr_data = attribute.data.data_for_time(frame_time);
+ const array<char> *attr_data = attribute.data.data_for_time(frame_time).get_data_or_null();
Attribute *attr = nullptr;
if (attribute.std != ATTR_STD_NONE) {
@@ -1278,6 +1291,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data,
}
memcpy(attr->data(), attr_data->data(), attr_data->size());
+ attr->modified = true;
}
/* remove any attributes not in cached_attributes */
@@ -1285,6 +1299,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data,
for (it = attributes.attributes.begin(); it != attributes.attributes.end();) {
if (cached_attributes.find(&(*it)) == cached_attributes.end()) {
attributes.attributes.erase(it++);
+ attributes.modified = true;
continue;
}
@@ -1305,12 +1320,12 @@ NODE_DEFINE(AlembicProcedural)
SOCKET_FLOAT(default_radius, "Default Radius", 0.01f);
SOCKET_FLOAT(scale, "Scale", 1.0f);
- SOCKET_NODE_ARRAY(objects, "Objects", &AlembicObject::node_type);
+ SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type());
return type;
}
-AlembicProcedural::AlembicProcedural() : Procedural(node_type)
+AlembicProcedural::AlembicProcedural() : Procedural(get_node_type())
{
objects_loaded = false;
scene_ = nullptr;
@@ -1358,11 +1373,16 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
}
bool need_shader_updates = false;
+ bool need_data_updates = false;
- /* Check for changes in shaders (newly requested attributes). */
foreach (Node *object_node, objects) {
AlembicObject *object = static_cast<AlembicObject *>(object_node);
+ if (object->is_modified()) {
+ need_data_updates = true;
+ }
+
+ /* Check for changes in shaders (e.g. newly requested attributes). */
foreach (Node *shader_node, object->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(shader_node);
@@ -1373,7 +1393,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
}
}
- if (!is_modified() && !need_shader_updates) {
+ if (!is_modified() && !need_shader_updates && !need_data_updates) {
return;
}
@@ -1397,6 +1417,8 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate);
+ build_caches(progress);
+
foreach (Node *node, objects) {
AlembicObject *object = static_cast<AlembicObject *>(node);
@@ -1405,19 +1427,19 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
}
/* skip constant objects */
- if (object->has_data_loaded() && object->is_constant() && !object->is_modified() &&
- !object->need_shader_update && !scale_is_modified()) {
+ if (object->is_constant() && !object->is_modified() && !object->need_shader_update &&
+ !scale_is_modified()) {
continue;
}
if (object->schema_type == AlembicObject::POLY_MESH) {
- read_mesh(scene, object, frame_time, progress);
+ read_mesh(object, frame_time);
}
else if (object->schema_type == AlembicObject::CURVES) {
- read_curves(scene, object, frame_time, progress);
+ read_curves(object, frame_time);
}
else if (object->schema_type == AlembicObject::SUBD) {
- read_subd(scene, object, frame_time, progress);
+ read_subd(object, frame_time);
}
object->clear_modified();
@@ -1471,7 +1493,7 @@ void AlembicProcedural::load_objects(Progress &progress)
IObject root = archive.getTop();
for (size_t i = 0; i < root.getNumChildren(); ++i) {
- walk_hierarchy(root, root.getChildHeader(i), nullptr, object_map, progress);
+ walk_hierarchy(root, root.getChildHeader(i), {}, object_map, progress);
}
/* Create nodes in the scene. */
@@ -1480,22 +1502,24 @@ void AlembicProcedural::load_objects(Progress &progress)
Geometry *geometry = nullptr;
- if (abc_object->schema_type == AlembicObject::CURVES) {
- geometry = scene_->create_node<Hair>();
- }
- else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
- abc_object->schema_type == AlembicObject::SUBD) {
- geometry = scene_->create_node<Mesh>();
- }
- else {
- continue;
- }
+ if (!abc_object->instance_of) {
+ if (abc_object->schema_type == AlembicObject::CURVES) {
+ geometry = scene_->create_node<Hair>();
+ }
+ else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
+ abc_object->schema_type == AlembicObject::SUBD) {
+ geometry = scene_->create_node<Mesh>();
+ }
+ else {
+ continue;
+ }
- geometry->set_owner(this);
- geometry->name = abc_object->iobject.getName();
+ geometry->set_owner(this);
+ geometry->name = abc_object->iobject.getName();
- array<Node *> used_shaders = abc_object->get_used_shaders();
- geometry->set_used_shaders(used_shaders);
+ array<Node *> used_shaders = abc_object->get_used_shaders();
+ geometry->set_used_shaders(used_shaders);
+ }
Object *object = scene_->create_node<Object>();
object->set_owner(this);
@@ -1504,43 +1528,44 @@ void AlembicProcedural::load_objects(Progress &progress)
abc_object->set_object(object);
}
+
+ /* Share geometries between instances. */
+ foreach (Node *node, objects) {
+ AlembicObject *abc_object = static_cast<AlembicObject *>(node);
+
+ if (abc_object->instance_of) {
+ abc_object->get_object()->set_geometry(
+ abc_object->instance_of->get_object()->get_geometry());
+ abc_object->schema_type = abc_object->instance_of->schema_type;
+ }
+ }
}
-void AlembicProcedural::read_mesh(Scene *scene,
- AlembicObject *abc_object,
- Abc::chrono_t frame_time,
- Progress &progress)
+void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time)
{
- IPolyMesh polymesh(abc_object->iobject, Alembic::Abc::kWrapExisting);
+ CachedData &cached_data = abc_object->get_cached_data();
- Mesh *mesh = static_cast<Mesh *>(abc_object->get_object()->get_geometry());
+ /* update sockets */
- CachedData &cached_data = abc_object->get_cached_data();
- IPolyMeshSchema schema = polymesh.getSchema();
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
- if (!abc_object->has_data_loaded()) {
- abc_object->load_all_data(this, schema, scale, progress);
+ if (object->is_modified()) {
+ object->tag_update(scene_);
}
- else {
- if (abc_object->need_shader_update) {
- abc_object->update_shader_attributes(schema.getArbGeomParams(), progress);
- }
- if (scale_is_modified()) {
- abc_object->setup_transform_cache(scale);
- }
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
}
- /* update sockets */
-
- Object *object = abc_object->get_object();
- cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+ Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket());
- array<int3> *triangle_data = cached_data.triangles.data_for_time(frame_time);
+ array<int3> *triangle_data = cached_data.triangles.data_for_time(frame_time).get_data_or_null();
if (triangle_data) {
array<int> triangles;
array<bool> smooth;
@@ -1566,7 +1591,7 @@ void AlembicProcedural::read_mesh(Scene *scene,
/* we don't yet support arbitrary attributes, for now add vertex
* coordinates as generated coordinates if requested */
- if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
memcpy(
attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
@@ -1574,46 +1599,35 @@ void AlembicProcedural::read_mesh(Scene *scene,
if (mesh->is_modified()) {
bool need_rebuild = mesh->triangles_is_modified();
- mesh->tag_update(scene, need_rebuild);
+ mesh->tag_update(scene_, need_rebuild);
}
}
-void AlembicProcedural::read_subd(Scene *scene,
- AlembicObject *abc_object,
- Abc::chrono_t frame_time,
- Progress &progress)
+void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time)
{
- ISubD subd_mesh(abc_object->iobject, Alembic::Abc::kWrapExisting);
- ISubDSchema schema = subd_mesh.getSchema();
-
- Mesh *mesh = static_cast<Mesh *>(abc_object->get_object()->get_geometry());
-
- /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */
- mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK);
+ CachedData &cached_data = abc_object->get_cached_data();
- if (!abc_object->has_data_loaded()) {
- abc_object->load_all_data(this, schema, scale, progress);
+ if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
+ /* need to reset the current data is something changed */
+ cached_data.invalidate_last_loaded_time();
}
- else {
- if (abc_object->need_shader_update) {
- abc_object->update_shader_attributes(schema.getArbGeomParams(), progress);
- }
- if (scale_is_modified()) {
- abc_object->setup_transform_cache(scale);
- }
- }
+ /* Update sockets. */
- mesh->set_subd_max_level(abc_object->get_subd_max_level());
- mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate());
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
- CachedData &cached_data = abc_object->get_cached_data();
+ if (object->is_modified()) {
+ object->tag_update(scene_);
+ }
- if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
- /* need to reset the current data is something changed */
- cached_data.invalidate_last_loaded_time();
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
}
+ Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+
/* Cycles overwrites the original triangles when computing displacement, so we always have to
* repass the data if something is animated (vertices most likely) to avoid buffer overflows. */
if (!cached_data.is_constant()) {
@@ -1626,10 +1640,10 @@ void AlembicProcedural::read_subd(Scene *scene,
mesh->clear_non_sockets();
- /* Update sockets. */
-
- Object *object = abc_object->get_object();
- cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+ /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */
+ mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK);
+ mesh->set_subd_max_level(abc_object->get_subd_max_level());
+ mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate());
cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
@@ -1666,7 +1680,7 @@ void AlembicProcedural::read_subd(Scene *scene,
/* we don't yet support arbitrary attributes, for now add vertex
* coordinates as generated coordinates if requested */
- if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
memcpy(
attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
@@ -1680,30 +1694,12 @@ void AlembicProcedural::read_subd(Scene *scene,
(mesh->subd_start_corner_is_modified()) ||
(mesh->subd_face_corners_is_modified());
- mesh->tag_update(scene, need_rebuild);
+ mesh->tag_update(scene_, need_rebuild);
}
}
-void AlembicProcedural::read_curves(Scene *scene,
- AlembicObject *abc_object,
- Abc::chrono_t frame_time,
- Progress &progress)
+void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t frame_time)
{
- ICurves curves(abc_object->iobject, Alembic::Abc::kWrapExisting);
- Hair *hair = static_cast<Hair *>(abc_object->get_object()->get_geometry());
-
- ICurvesSchema schema = curves.getSchema();
-
- if (!abc_object->has_data_loaded() || default_radius_is_modified() ||
- abc_object->radius_scale_is_modified()) {
- abc_object->load_all_data(this, schema, scale, progress, default_radius);
- }
- else {
- if (scale_is_modified()) {
- abc_object->setup_transform_cache(scale);
- }
- }
-
CachedData &cached_data = abc_object->get_cached_data();
/* update sockets */
@@ -1711,6 +1707,17 @@ void AlembicProcedural::read_curves(Scene *scene,
Object *object = abc_object->get_object();
cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+ if (object->is_modified()) {
+ object->tag_update(scene_);
+ }
+
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
+ }
+
+ Hair *hair = static_cast<Hair *>(object->get_geometry());
+
cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket());
cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket());
@@ -1725,7 +1732,7 @@ void AlembicProcedural::read_curves(Scene *scene,
/* we don't yet support arbitrary attributes, for now add first keys as generated coordinates if
* requested */
- if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
+ if (hair->need_attribute(scene_, ATTR_STD_GENERATED)) {
Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
float3 *generated = attr_generated->data_float3();
@@ -1735,13 +1742,13 @@ void AlembicProcedural::read_curves(Scene *scene,
}
const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
- hair->tag_update(scene, rebuild);
+ hair->tag_update(scene_, rebuild);
}
void AlembicProcedural::walk_hierarchy(
IObject parent,
const ObjectHeader &header,
- MatrixSampleMap *xform_samples,
+ MatrixSamplesData matrix_samples_data,
const unordered_map<std::string, AlembicObject *> &object_map,
Progress &progress)
{
@@ -1763,7 +1770,7 @@ void AlembicProcedural::walk_hierarchy(
MatrixSampleMap local_xform_samples;
MatrixSampleMap *temp_xform_samples = nullptr;
- if (xform_samples == nullptr) {
+ if (matrix_samples_data.samples == nullptr) {
/* If there is no parent transforms, fill the map directly. */
temp_xform_samples = &concatenated_xform_samples;
}
@@ -1778,11 +1785,13 @@ void AlembicProcedural::walk_hierarchy(
temp_xform_samples->insert({sample_time, sample.getMatrix()});
}
- if (xform_samples != nullptr) {
- concatenate_xform_samples(*xform_samples, local_xform_samples, concatenated_xform_samples);
+ if (matrix_samples_data.samples != nullptr) {
+ concatenate_xform_samples(
+ *matrix_samples_data.samples, local_xform_samples, concatenated_xform_samples);
}
- xform_samples = &concatenated_xform_samples;
+ matrix_samples_data.samples = &concatenated_xform_samples;
+ matrix_samples_data.time_sampling = ts;
}
next_object = xform;
@@ -1798,8 +1807,9 @@ void AlembicProcedural::walk_hierarchy(
abc_object->iobject = subd;
abc_object->schema_type = AlembicObject::SUBD;
- if (xform_samples) {
- abc_object->xform_samples = *xform_samples;
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
}
}
@@ -1816,8 +1826,9 @@ void AlembicProcedural::walk_hierarchy(
abc_object->iobject = mesh;
abc_object->schema_type = AlembicObject::POLY_MESH;
- if (xform_samples) {
- abc_object->xform_samples = *xform_samples;
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
}
}
@@ -1834,8 +1845,9 @@ void AlembicProcedural::walk_hierarchy(
abc_object->iobject = curves;
abc_object->schema_type = AlembicObject::CURVES;
- if (xform_samples) {
- abc_object->xform_samples = *xform_samples;
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
}
}
@@ -1844,15 +1856,92 @@ void AlembicProcedural::walk_hierarchy(
else if (IFaceSet::matches(header)) {
// ignore the face set, it will be read along with the data
}
+ else if (IPoints::matches(header)) {
+ // unsupported for now
+ }
+ else if (INuPatch::matches(header)) {
+ // unsupported for now
+ }
else {
- // unsupported type for now (Points, NuPatch)
next_object = parent.getChild(header.getName());
+
+ if (next_object.isInstanceRoot()) {
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+
+ /* Was this object asked to be rendered? */
+ iter = object_map.find(next_object.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+
+ /* Only try to render an instance if the original object is also rendered. */
+ iter = object_map.find(next_object.instanceSourcePath());
+
+ if (iter != object_map.end()) {
+ abc_object->iobject = next_object;
+ abc_object->instance_of = iter->second;
+
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
+ }
+ }
+ }
+ }
}
if (next_object.valid()) {
for (size_t i = 0; i < next_object.getNumChildren(); ++i) {
walk_hierarchy(
- next_object, next_object.getChildHeader(i), xform_samples, object_map, progress);
+ next_object, next_object.getChildHeader(i), matrix_samples_data, object_map, progress);
+ }
+ }
+}
+
+void AlembicProcedural::build_caches(Progress &progress)
+{
+ for (Node *node : objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ if (object->schema_type == AlembicObject::POLY_MESH) {
+ if (!object->has_data_loaded()) {
+ IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
+ IPolyMeshSchema schema = polymesh.getSchema();
+ object->load_all_data(this, schema, progress);
+ }
+ else if (object->need_shader_update) {
+ IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
+ IPolyMeshSchema schema = polymesh.getSchema();
+ object->update_shader_attributes(schema.getArbGeomParams(), progress);
+ }
+ }
+ else if (object->schema_type == AlembicObject::CURVES) {
+ if (!object->has_data_loaded() || default_radius_is_modified() ||
+ object->radius_scale_is_modified()) {
+ ICurves curves(object->iobject, Alembic::Abc::kWrapExisting);
+ ICurvesSchema schema = curves.getSchema();
+ object->load_all_data(this, schema, progress, default_radius);
+ }
+ }
+ else if (object->schema_type == AlembicObject::SUBD) {
+ if (!object->has_data_loaded()) {
+ ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
+ ISubDSchema schema = subd_mesh.getSchema();
+ object->load_all_data(this, schema, progress);
+ }
+ else if (object->need_shader_update) {
+ ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
+ ISubDSchema schema = subd_mesh.getSchema();
+ object->update_shader_attributes(schema.getArbGeomParams(), progress);
+ }
+ }
+
+ if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) {
+ object->setup_transform_cache(scale);
}
}
}
diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h
index b986f46bc8a..0fc02f1da23 100644
--- a/intern/cycles/render/alembic.h
+++ b/intern/cycles/render/alembic.h
@@ -38,6 +38,11 @@ class Shader;
using MatrixSampleMap = std::map<Alembic::Abc::chrono_t, Alembic::Abc::M44d>;
+struct MatrixSamplesData {
+ MatrixSampleMap *samples = nullptr;
+ Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling;
+};
+
/* Helpers to detect if some type is a ccl::array. */
template<typename> struct is_array : public std::false_type {
};
@@ -45,6 +50,78 @@ template<typename> struct is_array : public std::false_type {
template<typename T> struct is_array<array<T>> : public std::true_type {
};
+/* Holds the data for a cache lookup at a given time, as well as informations to
+ * help disambiguate successes or failures to get data from the cache. */
+template<typename T> class CacheLookupResult {
+ enum class State {
+ NEW_DATA,
+ ALREADY_LOADED,
+ NO_DATA_FOR_TIME,
+ };
+
+ T *data;
+ State state;
+
+ protected:
+ /* Prevent default construction outside of the class: for a valid result, we
+ * should use the static functions below. */
+ CacheLookupResult() = default;
+
+ public:
+ static CacheLookupResult new_data(T *data_)
+ {
+ CacheLookupResult result;
+ result.data = data_;
+ result.state = State::NEW_DATA;
+ return result;
+ }
+
+ static CacheLookupResult no_data_found_for_time()
+ {
+ CacheLookupResult result;
+ result.data = nullptr;
+ result.state = State::NO_DATA_FOR_TIME;
+ return result;
+ }
+
+ static CacheLookupResult already_loaded()
+ {
+ CacheLookupResult result;
+ result.data = nullptr;
+ result.state = State::ALREADY_LOADED;
+ return result;
+ }
+
+ /* This should only be call if new data is available. */
+ const T &get_data() const
+ {
+ assert(state == State::NEW_DATA);
+ assert(data != nullptr);
+ return *data;
+ }
+
+ T *get_data_or_null() const
+ {
+ // data_ should already be null if there is no new data so no need to check
+ return data;
+ }
+
+ bool has_new_data() const
+ {
+ return state == State::NEW_DATA;
+ }
+
+ bool has_already_loaded() const
+ {
+ return state == State::ALREADY_LOADED;
+ }
+
+ bool has_no_data_for_time() const
+ {
+ return state == State::NO_DATA_FOR_TIME;
+ }
+};
+
/* Store the data set for an animation at every time points, or at the beginning of the animation
* for constant data.
*
@@ -74,10 +151,10 @@ template<typename T> class DataStore {
/* Get the data for the specified time.
* Return nullptr if there is no data or if the data for this time was already loaded. */
- T *data_for_time(double time)
+ CacheLookupResult<T> data_for_time(double time)
{
if (size() == 0) {
- return nullptr;
+ return CacheLookupResult<T>::no_data_found_for_time();
}
std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
@@ -85,26 +162,26 @@ template<typename T> class DataStore {
DataTimePair &data_pair = data[index_pair.first];
if (last_loaded_time == data_pair.time) {
- return nullptr;
+ return CacheLookupResult<T>::already_loaded();
}
last_loaded_time = data_pair.time;
- return &data_pair.data;
+ return CacheLookupResult<T>::new_data(&data_pair.data);
}
/* get the data for the specified time, but do not check if the data was already loaded for this
* time return nullptr if there is no data */
- T *data_for_time_no_check(double time)
+ CacheLookupResult<T> data_for_time_no_check(double time)
{
if (size() == 0) {
- return nullptr;
+ return CacheLookupResult<T>::no_data_found_for_time();
}
std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
index_pair = time_sampling.getNearIndex(time, data.size());
DataTimePair &data_pair = data[index_pair.first];
- return &data_pair.data;
+ return CacheLookupResult<T>::new_data(&data_pair.data);
}
void add_data(T &data_, double time)
@@ -144,15 +221,15 @@ template<typename T> class DataStore {
* data for this time or it was already loaded, do nothing. */
void copy_to_socket(double time, Node *node, const SocketType *socket)
{
- T *data_ = data_for_time(time);
+ CacheLookupResult<T> result = data_for_time(time);
- if (data_ == nullptr) {
+ if (!result.has_new_data()) {
return;
}
/* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the
* arrays to avoid reloading the data */
- T value = *data_;
+ T value = result.get_data();
node->set(*socket, value);
}
};
@@ -249,15 +326,12 @@ class AlembicObject : public Node {
void load_all_data(AlembicProcedural *proc,
Alembic::AbcGeom::IPolyMeshSchema &schema,
- float scale,
Progress &progress);
void load_all_data(AlembicProcedural *proc,
Alembic::AbcGeom::ISubDSchema &schema,
- float scale,
Progress &progress);
void load_all_data(AlembicProcedural *proc,
const Alembic::AbcGeom::ICurvesSchema &schema,
- float scale,
Progress &progress,
float default_radius);
@@ -274,6 +348,9 @@ class AlembicObject : public Node {
bool need_shader_update = true;
+ AlembicObject *instance_of = nullptr;
+
+ Alembic::AbcCoreAbstract::TimeSamplingPtr xform_time_sampling;
MatrixSampleMap xform_samples;
Alembic::AbcGeom::IObject iobject;
@@ -384,30 +461,23 @@ class AlembicProcedural : public Procedural {
* way for each IObject. */
void walk_hierarchy(Alembic::AbcGeom::IObject parent,
const Alembic::AbcGeom::ObjectHeader &ohead,
- MatrixSampleMap *xform_samples,
+ MatrixSamplesData matrix_samples_data,
const unordered_map<string, AlembicObject *> &object_map,
Progress &progress);
/* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and
* Object Nodes in the Cycles scene if none exist yet. */
- void read_mesh(Scene *scene,
- AlembicObject *abc_object,
- Alembic::AbcGeom::Abc::chrono_t frame_time,
- Progress &progress);
+ void read_mesh(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
/* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and
* Object Nodes in the Cycles scene if none exist yet. */
- void read_curves(Scene *scene,
- AlembicObject *abc_object,
- Alembic::AbcGeom::Abc::chrono_t frame_time,
- Progress &progress);
+ void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
/* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
* Object Nodes in the Cycles scene if none exist yet. */
- void read_subd(Scene *scene,
- AlembicObject *abc_object,
- Alembic::AbcGeom::Abc::chrono_t frame_time,
- Progress &progress);
+ void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
+
+ void build_caches(Progress &progress);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index 1303f894912..b3d383afae4 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -47,12 +47,12 @@ NODE_DEFINE(Background)
SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f);
- SOCKET_NODE(shader, "Shader", &Shader::node_type);
+ SOCKET_NODE(shader, "Shader", Shader::get_node_type());
return type;
}
-Background::Background() : Node(node_type)
+Background::Background() : Node(get_node_type())
{
shader = NULL;
}
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index afe788eb4be..327f166f9d8 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -163,7 +163,7 @@ NODE_DEFINE(Camera)
return type;
}
-Camera::Camera() : Node(node_type)
+Camera::Camera() : Node(get_node_type())
{
shutter_table_offset = TABLE_OFFSET_INVALID;
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 9b7657802d6..c4ff89fc838 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -96,7 +96,7 @@ NODE_DEFINE(Pass)
return type;
}
-Pass::Pass() : Node(node_type)
+Pass::Pass() : Node(get_node_type())
{
}
@@ -407,7 +407,7 @@ NODE_DEFINE(Film)
return type;
}
-Film::Film() : Node(node_type)
+Film::Film() : Node(get_node_type())
{
use_light_visibility = false;
filter_table_offset = TABLE_OFFSET_INVALID;
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 9f8bf68dadf..537f3d98c5c 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -52,7 +52,7 @@ NODE_ABSTRACT_DEFINE(Geometry)
SOCKET_UINT(motion_steps, "Motion Steps", 3);
SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
- SOCKET_NODE_ARRAY(used_shaders, "Shaders", &Shader::node_type);
+ SOCKET_NODE_ARRAY(used_shaders, "Shaders", Shader::get_node_type());
return type;
}
@@ -1367,7 +1367,7 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
/* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
- dscene->data.bvh.scene = NULL;
+ dscene->data.bvh.scene = 0;
}
/* Set of flags used to help determining what data has been modified or needs reallocation, so we
diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp
index 28ad8a1461a..dad235aa340 100644
--- a/intern/cycles/render/hair.cpp
+++ b/intern/cycles/render/hair.cpp
@@ -283,7 +283,7 @@ void Hair::Curve::cardinal_keys_for_step(const float3 *curve_keys,
NODE_DEFINE(Hair)
{
- NodeType *type = NodeType::add("hair", create, NodeType::NONE, Geometry::node_base_type);
+ NodeType *type = NodeType::add("hair", create, NodeType::NONE, Geometry::get_node_base_type());
SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>());
SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>());
@@ -293,7 +293,7 @@ NODE_DEFINE(Hair)
return type;
}
-Hair::Hair() : Geometry(node_type, Geometry::HAIR)
+Hair::Hair() : Geometry(get_node_type(), Geometry::HAIR)
{
curvekey_offset = 0;
curve_shape = CURVE_RIBBON;
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index d93856ceb61..d8749cec9fa 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -96,7 +96,7 @@ NODE_DEFINE(Integrator)
return type;
}
-Integrator::Integrator() : Node(node_type)
+Integrator::Integrator() : Node(get_node_type())
{
}
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index d1e64e2ac14..72450e2c546 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -151,12 +151,12 @@ NODE_DEFINE(Light)
SOCKET_BOOLEAN(is_portal, "Is Portal", false);
SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
- SOCKET_NODE(shader, "Shader", &Shader::node_type);
+ SOCKET_NODE(shader, "Shader", Shader::get_node_type());
return type;
}
-Light::Light() : Node(node_type)
+Light::Light() : Node(get_node_type())
{
}
@@ -609,7 +609,7 @@ void LightManager::device_update_background(Device *device,
Shader *shader = scene->background->get_shader(scene);
int num_suns = 0;
foreach (ShaderNode *node, shader->graph->nodes) {
- if (node->type == EnvironmentTextureNode::node_type) {
+ if (node->type == EnvironmentTextureNode::get_node_type()) {
EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
ImageMetaData metadata;
if (!env->handle.empty()) {
@@ -618,7 +618,7 @@ void LightManager::device_update_background(Device *device,
environment_res.y = max(environment_res.y, metadata.height);
}
}
- if (node->type == SkyTextureNode::node_type) {
+ if (node->type == SkyTextureNode::get_node_type()) {
SkyTextureNode *sky = (SkyTextureNode *)node;
if (sky->get_sky_type() == NODE_SKY_NISHITA && sky->get_sun_disc()) {
/* Ensure that the input coordinates aren't transformed before they reach the node.
@@ -627,7 +627,7 @@ void LightManager::device_update_background(Device *device,
const ShaderInput *vec_in = sky->input("Vector");
if (vec_in && vec_in->link && vec_in->link->parent) {
ShaderNode *vec_src = vec_in->link->parent;
- if ((vec_src->type != TextureCoordinateNode::node_type) ||
+ if ((vec_src->type != TextureCoordinateNode::get_node_type()) ||
(vec_in->link != vec_src->output("Generated"))) {
environment_res.x = max(environment_res.x, 4096);
environment_res.y = max(environment_res.y, 2048);
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 1f6fcdd0abe..d5e5b960665 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -125,7 +125,7 @@ float3 Mesh::SubdFace::normal(const Mesh *mesh) const
NODE_DEFINE(Mesh)
{
- NodeType *type = NodeType::add("mesh", create, NodeType::NONE, Geometry::node_base_type);
+ NodeType *type = NodeType::add("mesh", create, NodeType::NONE, Geometry::get_node_base_type());
SOCKET_INT_ARRAY(triangles, "Triangles", array<int>());
SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>());
@@ -202,7 +202,7 @@ Mesh::Mesh(const NodeType *node_type, Type geom_type_)
patch_table = NULL;
}
-Mesh::Mesh() : Mesh(node_type, Geometry::MESH)
+Mesh::Mesh() : Mesh(get_node_type(), Geometry::MESH)
{
}
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index b17f1ec0b2f..7d485fa3f03 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -258,7 +258,7 @@ NODE_DEFINE(ImageTextureNode)
return type;
}
-ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
+ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(get_node_type())
{
colorspace = u_colorspace_raw;
animated = false;
@@ -309,11 +309,11 @@ void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
ustring attribute;
if (vector_in->link) {
ShaderNode *node = vector_in->link->parent;
- if (node->type == UVMapNode::node_type) {
+ if (node->type == UVMapNode::get_node_type()) {
UVMapNode *uvmap = (UVMapNode *)node;
attribute = uvmap->get_attribute();
}
- else if (node->type == TextureCoordinateNode::node_type) {
+ else if (node->type == TextureCoordinateNode::get_node_type()) {
if (vector_in->link != node->output("UV")) {
return;
}
@@ -525,7 +525,7 @@ NODE_DEFINE(EnvironmentTextureNode)
return type;
}
-EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_type)
+EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(get_node_type())
{
colorspace = u_colorspace_raw;
animated = false;
@@ -818,7 +818,7 @@ NODE_DEFINE(SkyTextureNode)
return type;
}
-SkyTextureNode::SkyTextureNode() : TextureNode(node_type)
+SkyTextureNode::SkyTextureNode() : TextureNode(get_node_type())
{
}
@@ -1000,7 +1000,7 @@ NODE_DEFINE(GradientTextureNode)
return type;
}
-GradientTextureNode::GradientTextureNode() : TextureNode(node_type)
+GradientTextureNode::GradientTextureNode() : TextureNode(get_node_type())
{
}
@@ -1057,7 +1057,7 @@ NODE_DEFINE(NoiseTextureNode)
return type;
}
-NoiseTextureNode::NoiseTextureNode() : TextureNode(node_type)
+NoiseTextureNode::NoiseTextureNode() : TextureNode(get_node_type())
{
}
@@ -1150,7 +1150,7 @@ NODE_DEFINE(VoronoiTextureNode)
return type;
}
-VoronoiTextureNode::VoronoiTextureNode() : TextureNode(node_type)
+VoronoiTextureNode::VoronoiTextureNode() : TextureNode(get_node_type())
{
}
@@ -1229,7 +1229,7 @@ NODE_DEFINE(IESLightNode)
return type;
}
-IESLightNode::IESLightNode() : TextureNode(node_type)
+IESLightNode::IESLightNode() : TextureNode(get_node_type())
{
light_manager = NULL;
slot = -1;
@@ -1321,7 +1321,7 @@ NODE_DEFINE(WhiteNoiseTextureNode)
return type;
}
-WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(node_type)
+WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(get_node_type())
{
}
@@ -1386,7 +1386,7 @@ NODE_DEFINE(MusgraveTextureNode)
return type;
}
-MusgraveTextureNode::MusgraveTextureNode() : TextureNode(node_type)
+MusgraveTextureNode::MusgraveTextureNode() : TextureNode(get_node_type())
{
}
@@ -1484,7 +1484,7 @@ NODE_DEFINE(WaveTextureNode)
return type;
}
-WaveTextureNode::WaveTextureNode() : TextureNode(node_type)
+WaveTextureNode::WaveTextureNode() : TextureNode(get_node_type())
{
}
@@ -1558,7 +1558,7 @@ NODE_DEFINE(MagicTextureNode)
return type;
}
-MagicTextureNode::MagicTextureNode() : TextureNode(node_type)
+MagicTextureNode::MagicTextureNode() : TextureNode(get_node_type())
{
}
@@ -1611,7 +1611,7 @@ NODE_DEFINE(CheckerTextureNode)
return type;
}
-CheckerTextureNode::CheckerTextureNode() : TextureNode(node_type)
+CheckerTextureNode::CheckerTextureNode() : TextureNode(get_node_type())
{
}
@@ -1677,7 +1677,7 @@ NODE_DEFINE(BrickTextureNode)
return type;
}
-BrickTextureNode::BrickTextureNode() : TextureNode(node_type)
+BrickTextureNode::BrickTextureNode() : TextureNode(get_node_type())
{
}
@@ -1770,7 +1770,7 @@ NODE_DEFINE(PointDensityTextureNode)
return type;
}
-PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(node_type)
+PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(get_node_type())
{
}
@@ -1887,7 +1887,7 @@ NODE_DEFINE(NormalNode)
return type;
}
-NormalNode::NormalNode() : ShaderNode(node_type)
+NormalNode::NormalNode() : ShaderNode(get_node_type())
{
}
@@ -1934,7 +1934,7 @@ NODE_DEFINE(MappingNode)
return type;
}
-MappingNode::MappingNode() : ShaderNode(node_type)
+MappingNode::MappingNode() : ShaderNode(get_node_type())
{
}
@@ -1989,7 +1989,7 @@ NODE_DEFINE(RGBToBWNode)
return type;
}
-RGBToBWNode::RGBToBWNode() : ShaderNode(node_type)
+RGBToBWNode::RGBToBWNode() : ShaderNode(get_node_type())
{
}
@@ -2312,7 +2312,7 @@ NODE_DEFINE(AnisotropicBsdfNode)
return type;
}
-AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(node_type)
+AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
}
@@ -2370,7 +2370,7 @@ NODE_DEFINE(GlossyBsdfNode)
return type;
}
-GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(node_type)
+GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
distribution_orig = NBUILTIN_CLOSURES;
@@ -2463,7 +2463,7 @@ NODE_DEFINE(GlassBsdfNode)
return type;
}
-GlassBsdfNode::GlassBsdfNode() : BsdfNode(node_type)
+GlassBsdfNode::GlassBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
distribution_orig = NBUILTIN_CLOSURES;
@@ -2556,7 +2556,7 @@ NODE_DEFINE(RefractionBsdfNode)
return type;
}
-RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(node_type)
+RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_REFRACTION_ID;
distribution_orig = NBUILTIN_CLOSURES;
@@ -2644,7 +2644,7 @@ NODE_DEFINE(ToonBsdfNode)
return type;
}
-ToonBsdfNode::ToonBsdfNode() : BsdfNode(node_type)
+ToonBsdfNode::ToonBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
}
@@ -2678,7 +2678,7 @@ NODE_DEFINE(VelvetBsdfNode)
return type;
}
-VelvetBsdfNode::VelvetBsdfNode() : BsdfNode(node_type)
+VelvetBsdfNode::VelvetBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
}
@@ -2709,7 +2709,7 @@ NODE_DEFINE(DiffuseBsdfNode)
return type;
}
-DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(node_type)
+DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_DIFFUSE_ID;
}
@@ -2773,7 +2773,7 @@ NODE_DEFINE(PrincipledBsdfNode)
return type;
}
-PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(node_type)
+PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type())
{
closure = CLOSURE_BSDF_PRINCIPLED_ID;
distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
@@ -2994,7 +2994,7 @@ NODE_DEFINE(TranslucentBsdfNode)
return type;
}
-TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(node_type)
+TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_TRANSLUCENT_ID;
}
@@ -3023,7 +3023,7 @@ NODE_DEFINE(TransparentBsdfNode)
return type;
}
-TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(node_type)
+TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_TRANSPARENT_ID;
}
@@ -3064,7 +3064,7 @@ NODE_DEFINE(SubsurfaceScatteringNode)
return type;
}
-SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(node_type)
+SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(get_node_type())
{
closure = falloff;
}
@@ -3106,7 +3106,7 @@ NODE_DEFINE(EmissionNode)
return type;
}
-EmissionNode::EmissionNode() : ShaderNode(node_type)
+EmissionNode::EmissionNode() : ShaderNode(get_node_type())
{
}
@@ -3155,7 +3155,7 @@ NODE_DEFINE(BackgroundNode)
return type;
}
-BackgroundNode::BackgroundNode() : ShaderNode(node_type)
+BackgroundNode::BackgroundNode() : ShaderNode(get_node_type())
{
}
@@ -3203,7 +3203,7 @@ NODE_DEFINE(HoldoutNode)
return type;
}
-HoldoutNode::HoldoutNode() : ShaderNode(node_type)
+HoldoutNode::HoldoutNode() : ShaderNode(get_node_type())
{
}
@@ -3241,7 +3241,7 @@ NODE_DEFINE(AmbientOcclusionNode)
return type;
}
-AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(node_type)
+AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(get_node_type())
{
}
@@ -3329,7 +3329,7 @@ NODE_DEFINE(AbsorptionVolumeNode)
return type;
}
-AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(node_type)
+AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(get_node_type())
{
closure = CLOSURE_VOLUME_ABSORPTION_ID;
}
@@ -3360,7 +3360,7 @@ NODE_DEFINE(ScatterVolumeNode)
return type;
}
-ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(node_type)
+ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(get_node_type())
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
}
@@ -3401,7 +3401,7 @@ NODE_DEFINE(PrincipledVolumeNode)
return type;
}
-PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(node_type)
+PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(get_node_type())
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
density_attribute = ustring("density");
@@ -3526,7 +3526,7 @@ NODE_DEFINE(PrincipledHairBsdfNode)
return type;
}
-PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(node_type)
+PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
{
closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
}
@@ -3637,7 +3637,7 @@ NODE_DEFINE(HairBsdfNode)
return type;
}
-HairBsdfNode::HairBsdfNode() : BsdfNode(node_type)
+HairBsdfNode::HairBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
}
@@ -3677,7 +3677,7 @@ NODE_DEFINE(GeometryNode)
return type;
}
-GeometryNode::GeometryNode() : ShaderNode(node_type)
+GeometryNode::GeometryNode() : ShaderNode(get_node_type())
{
special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
}
@@ -3824,7 +3824,7 @@ NODE_DEFINE(TextureCoordinateNode)
return type;
}
-TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(node_type)
+TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(get_node_type())
{
}
@@ -3971,7 +3971,7 @@ NODE_DEFINE(UVMapNode)
return type;
}
-UVMapNode::UVMapNode() : ShaderNode(node_type)
+UVMapNode::UVMapNode() : ShaderNode(get_node_type())
{
}
@@ -4060,7 +4060,7 @@ NODE_DEFINE(LightPathNode)
return type;
}
-LightPathNode::LightPathNode() : ShaderNode(node_type)
+LightPathNode::LightPathNode() : ShaderNode(get_node_type())
{
}
@@ -4160,7 +4160,7 @@ NODE_DEFINE(LightFalloffNode)
return type;
}
-LightFalloffNode::LightFalloffNode() : ShaderNode(node_type)
+LightFalloffNode::LightFalloffNode() : ShaderNode(get_node_type())
{
}
@@ -4217,7 +4217,7 @@ NODE_DEFINE(ObjectInfoNode)
return type;
}
-ObjectInfoNode::ObjectInfoNode() : ShaderNode(node_type)
+ObjectInfoNode::ObjectInfoNode() : ShaderNode(get_node_type())
{
}
@@ -4275,7 +4275,7 @@ NODE_DEFINE(ParticleInfoNode)
return type;
}
-ParticleInfoNode::ParticleInfoNode() : ShaderNode(node_type)
+ParticleInfoNode::ParticleInfoNode() : ShaderNode(get_node_type())
{
}
@@ -4382,7 +4382,7 @@ NODE_DEFINE(HairInfoNode)
return type;
}
-HairInfoNode::HairInfoNode() : ShaderNode(node_type)
+HairInfoNode::HairInfoNode() : ShaderNode(get_node_type())
{
}
@@ -4457,7 +4457,7 @@ NODE_DEFINE(VolumeInfoNode)
return type;
}
-VolumeInfoNode::VolumeInfoNode() : ShaderNode(node_type)
+VolumeInfoNode::VolumeInfoNode() : ShaderNode(get_node_type())
{
}
@@ -4538,7 +4538,7 @@ NODE_DEFINE(VertexColorNode)
return type;
}
-VertexColorNode::VertexColorNode() : ShaderNode(node_type)
+VertexColorNode::VertexColorNode() : ShaderNode(get_node_type())
{
}
@@ -4619,7 +4619,7 @@ NODE_DEFINE(ValueNode)
return type;
}
-ValueNode::ValueNode() : ShaderNode(node_type)
+ValueNode::ValueNode() : ShaderNode(get_node_type())
{
}
@@ -4653,7 +4653,7 @@ NODE_DEFINE(ColorNode)
return type;
}
-ColorNode::ColorNode() : ShaderNode(node_type)
+ColorNode::ColorNode() : ShaderNode(get_node_type())
{
}
@@ -4692,7 +4692,7 @@ NODE_DEFINE(AddClosureNode)
return type;
}
-AddClosureNode::AddClosureNode() : ShaderNode(node_type)
+AddClosureNode::AddClosureNode() : ShaderNode(get_node_type())
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
}
@@ -4736,7 +4736,7 @@ NODE_DEFINE(MixClosureNode)
return type;
}
-MixClosureNode::MixClosureNode() : ShaderNode(node_type)
+MixClosureNode::MixClosureNode() : ShaderNode(get_node_type())
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
}
@@ -4790,7 +4790,7 @@ NODE_DEFINE(MixClosureWeightNode)
return type;
}
-MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(node_type)
+MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(get_node_type())
{
}
@@ -4827,7 +4827,7 @@ NODE_DEFINE(InvertNode)
return type;
}
-InvertNode::InvertNode() : ShaderNode(node_type)
+InvertNode::InvertNode() : ShaderNode(get_node_type())
{
}
@@ -4903,7 +4903,7 @@ NODE_DEFINE(MixNode)
return type;
}
-MixNode::MixNode() : ShaderNode(node_type)
+MixNode::MixNode() : ShaderNode(get_node_type())
{
}
@@ -4958,7 +4958,7 @@ NODE_DEFINE(CombineRGBNode)
return type;
}
-CombineRGBNode::CombineRGBNode() : ShaderNode(node_type)
+CombineRGBNode::CombineRGBNode() : ShaderNode(get_node_type())
{
}
@@ -5006,7 +5006,7 @@ NODE_DEFINE(CombineXYZNode)
return type;
}
-CombineXYZNode::CombineXYZNode() : ShaderNode(node_type)
+CombineXYZNode::CombineXYZNode() : ShaderNode(get_node_type())
{
}
@@ -5054,7 +5054,7 @@ NODE_DEFINE(CombineHSVNode)
return type;
}
-CombineHSVNode::CombineHSVNode() : ShaderNode(node_type)
+CombineHSVNode::CombineHSVNode() : ShaderNode(get_node_type())
{
}
@@ -5097,7 +5097,7 @@ NODE_DEFINE(GammaNode)
return type;
}
-GammaNode::GammaNode() : ShaderNode(node_type)
+GammaNode::GammaNode() : ShaderNode(get_node_type())
{
}
@@ -5153,7 +5153,7 @@ NODE_DEFINE(BrightContrastNode)
return type;
}
-BrightContrastNode::BrightContrastNode() : ShaderNode(node_type)
+BrightContrastNode::BrightContrastNode() : ShaderNode(get_node_type())
{
}
@@ -5198,7 +5198,7 @@ NODE_DEFINE(SeparateRGBNode)
return type;
}
-SeparateRGBNode::SeparateRGBNode() : ShaderNode(node_type)
+SeparateRGBNode::SeparateRGBNode() : ShaderNode(get_node_type())
{
}
@@ -5251,7 +5251,7 @@ NODE_DEFINE(SeparateXYZNode)
return type;
}
-SeparateXYZNode::SeparateXYZNode() : ShaderNode(node_type)
+SeparateXYZNode::SeparateXYZNode() : ShaderNode(get_node_type())
{
}
@@ -5304,7 +5304,7 @@ NODE_DEFINE(SeparateHSVNode)
return type;
}
-SeparateHSVNode::SeparateHSVNode() : ShaderNode(node_type)
+SeparateHSVNode::SeparateHSVNode() : ShaderNode(get_node_type())
{
}
@@ -5358,7 +5358,7 @@ NODE_DEFINE(HSVNode)
return type;
}
-HSVNode::HSVNode() : ShaderNode(node_type)
+HSVNode::HSVNode() : ShaderNode(get_node_type())
{
}
@@ -5401,7 +5401,7 @@ NODE_DEFINE(AttributeNode)
return type;
}
-AttributeNode::AttributeNode() : ShaderNode(node_type)
+AttributeNode::AttributeNode() : ShaderNode(get_node_type())
{
}
@@ -5489,7 +5489,7 @@ NODE_DEFINE(CameraNode)
return type;
}
-CameraNode::CameraNode() : ShaderNode(node_type)
+CameraNode::CameraNode() : ShaderNode(get_node_type())
{
}
@@ -5525,7 +5525,7 @@ NODE_DEFINE(FresnelNode)
return type;
}
-FresnelNode::FresnelNode() : ShaderNode(node_type)
+FresnelNode::FresnelNode() : ShaderNode(get_node_type())
{
}
@@ -5563,7 +5563,7 @@ NODE_DEFINE(LayerWeightNode)
return type;
}
-LayerWeightNode::LayerWeightNode() : ShaderNode(node_type)
+LayerWeightNode::LayerWeightNode() : ShaderNode(get_node_type())
{
}
@@ -5611,7 +5611,7 @@ NODE_DEFINE(WireframeNode)
return type;
}
-WireframeNode::WireframeNode() : ShaderNode(node_type)
+WireframeNode::WireframeNode() : ShaderNode(get_node_type())
{
}
@@ -5659,7 +5659,7 @@ NODE_DEFINE(WavelengthNode)
return type;
}
-WavelengthNode::WavelengthNode() : ShaderNode(node_type)
+WavelengthNode::WavelengthNode() : ShaderNode(get_node_type())
{
}
@@ -5689,7 +5689,7 @@ NODE_DEFINE(BlackbodyNode)
return type;
}
-BlackbodyNode::BlackbodyNode() : ShaderNode(node_type)
+BlackbodyNode::BlackbodyNode() : ShaderNode(get_node_type())
{
}
@@ -5728,7 +5728,7 @@ NODE_DEFINE(OutputNode)
return type;
}
-OutputNode::OutputNode() : ShaderNode(node_type)
+OutputNode::OutputNode() : ShaderNode(get_node_type())
{
special_type = SHADER_SPECIAL_TYPE_OUTPUT;
}
@@ -5780,7 +5780,7 @@ NODE_DEFINE(MapRangeNode)
return type;
}
-MapRangeNode::MapRangeNode() : ShaderNode(node_type)
+MapRangeNode::MapRangeNode() : ShaderNode(get_node_type())
{
}
@@ -5868,7 +5868,7 @@ NODE_DEFINE(ClampNode)
return type;
}
-ClampNode::ClampNode() : ShaderNode(node_type)
+ClampNode::ClampNode() : ShaderNode(get_node_type())
{
}
@@ -5923,7 +5923,7 @@ NODE_DEFINE(OutputAOVNode)
return type;
}
-OutputAOVNode::OutputAOVNode() : ShaderNode(node_type)
+OutputAOVNode::OutputAOVNode() : ShaderNode(get_node_type())
{
special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
slot = -1;
@@ -6021,7 +6021,7 @@ NODE_DEFINE(MathNode)
return type;
}
-MathNode::MathNode() : ShaderNode(node_type)
+MathNode::MathNode() : ShaderNode(get_node_type())
{
}
@@ -6124,7 +6124,7 @@ NODE_DEFINE(VectorMathNode)
return type;
}
-VectorMathNode::VectorMathNode() : ShaderNode(node_type)
+VectorMathNode::VectorMathNode() : ShaderNode(get_node_type())
{
}
@@ -6213,7 +6213,7 @@ NODE_DEFINE(VectorRotateNode)
return type;
}
-VectorRotateNode::VectorRotateNode() : ShaderNode(node_type)
+VectorRotateNode::VectorRotateNode() : ShaderNode(get_node_type())
{
}
@@ -6269,7 +6269,7 @@ NODE_DEFINE(VectorTransformNode)
return type;
}
-VectorTransformNode::VectorTransformNode() : ShaderNode(node_type)
+VectorTransformNode::VectorTransformNode() : ShaderNode(get_node_type())
{
}
@@ -6317,7 +6317,7 @@ NODE_DEFINE(BumpNode)
return type;
}
-BumpNode::BumpNode() : ShaderNode(node_type)
+BumpNode::BumpNode() : ShaderNode(get_node_type())
{
special_type = SHADER_SPECIAL_TYPE_BUMP;
}
@@ -6464,7 +6464,7 @@ NODE_DEFINE(RGBCurvesNode)
return type;
}
-RGBCurvesNode::RGBCurvesNode() : CurvesNode(node_type)
+RGBCurvesNode::RGBCurvesNode() : CurvesNode(get_node_type())
{
}
@@ -6501,7 +6501,7 @@ NODE_DEFINE(VectorCurvesNode)
return type;
}
-VectorCurvesNode::VectorCurvesNode() : CurvesNode(node_type)
+VectorCurvesNode::VectorCurvesNode() : CurvesNode(get_node_type())
{
}
@@ -6538,7 +6538,7 @@ NODE_DEFINE(RGBRampNode)
return type;
}
-RGBRampNode::RGBRampNode() : ShaderNode(node_type)
+RGBRampNode::RGBRampNode() : ShaderNode(get_node_type())
{
}
@@ -6611,7 +6611,7 @@ NODE_DEFINE(SetNormalNode)
return type;
}
-SetNormalNode::SetNormalNode() : ShaderNode(node_type)
+SetNormalNode::SetNormalNode() : ShaderNode(get_node_type())
{
}
@@ -6733,7 +6733,7 @@ NODE_DEFINE(NormalMapNode)
return type;
}
-NormalMapNode::NormalMapNode() : ShaderNode(node_type)
+NormalMapNode::NormalMapNode() : ShaderNode(get_node_type())
{
}
@@ -6827,7 +6827,7 @@ NODE_DEFINE(TangentNode)
return type;
}
-TangentNode::TangentNode() : ShaderNode(node_type)
+TangentNode::TangentNode() : ShaderNode(get_node_type())
{
}
@@ -6897,7 +6897,7 @@ NODE_DEFINE(BevelNode)
return type;
}
-BevelNode::BevelNode() : ShaderNode(node_type)
+BevelNode::BevelNode() : ShaderNode(get_node_type())
{
}
@@ -6942,7 +6942,7 @@ NODE_DEFINE(DisplacementNode)
return type;
}
-DisplacementNode::DisplacementNode() : ShaderNode(node_type)
+DisplacementNode::DisplacementNode() : ShaderNode(get_node_type())
{
}
@@ -7001,7 +7001,7 @@ NODE_DEFINE(VectorDisplacementNode)
return type;
}
-VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(node_type)
+VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(get_node_type())
{
}
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index ebbfc789329..e71d7d4a3eb 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -82,7 +82,7 @@ NODE_DEFINE(Object)
{
NodeType *type = NodeType::add("object", create);
- SOCKET_NODE(geometry, "Geometry", &Geometry::node_base_type);
+ SOCKET_NODE(geometry, "Geometry", Geometry::get_node_base_type());
SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
SOCKET_UINT(visibility, "Visibility", ~0);
SOCKET_COLOR(color, "Color", zero_float3());
@@ -98,13 +98,13 @@ NODE_DEFINE(Object)
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
- SOCKET_NODE(particle_system, "Particle System", &ParticleSystem::node_type);
+ SOCKET_NODE(particle_system, "Particle System", ParticleSystem::get_node_type());
SOCKET_INT(particle_index, "Particle Index", 0);
return type;
}
-Object::Object() : Node(node_type)
+Object::Object() : Node(get_node_type())
{
particle_system = NULL;
particle_index = 0;
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index 0e168050281..02dd1359b18 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -36,7 +36,7 @@ NODE_DEFINE(ParticleSystem)
return type;
}
-ParticleSystem::ParticleSystem() : Node(node_type)
+ParticleSystem::ParticleSystem() : Node(get_node_type())
{
}
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 6bb25677965..d3dfe1c5be6 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -91,6 +91,7 @@ DeviceScene::DeviceScene(Device *device)
Scene::Scene(const SceneParams &params_, Device *device)
: name("Scene"),
+ bvh(NULL),
default_surface(NULL),
default_volume(NULL),
default_light(NULL),
@@ -99,37 +100,36 @@ Scene::Scene(const SceneParams &params_, Device *device)
device(device),
dscene(device),
params(params_),
- update_stats(NULL)
+ update_stats(NULL),
+ kernels_loaded(false),
+ /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
+ max_closure_global(1)
{
memset((void *)&dscene.data, 0, sizeof(dscene.data));
- bvh = NULL;
- camera = create_node<Camera>();
- dicing_camera = create_node<Camera>();
- lookup_tables = new LookupTables();
- film = create_node<Film>();
- background = create_node<Background>();
+ /* OSL only works on the CPU */
+ if (device->info.has_osl)
+ shader_manager = ShaderManager::create(params.shadingsystem);
+ else
+ shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
+
light_manager = new LightManager();
geometry_manager = new GeometryManager();
object_manager = new ObjectManager();
- integrator = create_node<Integrator>();
image_manager = new ImageManager(device->info);
particle_system_manager = new ParticleSystemManager();
bake_manager = new BakeManager();
procedural_manager = new ProceduralManager();
- kernels_loaded = false;
- /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
- max_closure_global = 1;
+ /* Create nodes after managers, since create_node() can tag the managers. */
+ camera = create_node<Camera>();
+ dicing_camera = create_node<Camera>();
+ lookup_tables = new LookupTables();
+ film = create_node<Film>();
+ background = create_node<Background>();
+ integrator = create_node<Integrator>();
film->add_default(this);
-
- /* OSL only works on the CPU */
- if (device->info.has_osl)
- shader_manager = ShaderManager::create(params.shadingsystem);
- else
- shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
-
shader_manager->add_default(this);
}
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index ea83073d5ce..5ecbd92d96d 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -194,7 +194,7 @@ NODE_DEFINE(Shader)
return type;
}
-Shader::Shader() : Node(node_type)
+Shader::Shader() : Node(get_node_type())
{
pass_id = 0;
@@ -245,7 +245,7 @@ bool Shader::is_constant_emission(float3 *emission)
return false;
}
- if (surf->link->parent->type == EmissionNode::node_type) {
+ if (surf->link->parent->type == EmissionNode::get_node_type()) {
EmissionNode *node = (EmissionNode *)surf->link->parent;
assert(node->input("Color"));
@@ -257,7 +257,7 @@ bool Shader::is_constant_emission(float3 *emission)
*emission = node->get_color() * node->get_strength();
}
- else if (surf->link->parent->type == BackgroundNode::node_type) {
+ else if (surf->link->parent->type == BackgroundNode::get_node_type()) {
BackgroundNode *node = (BackgroundNode *)surf->link->parent;
assert(node->input("Color"));
@@ -831,7 +831,8 @@ static bool to_scene_linear_transform(OCIO::ConstConfigRcPtr &config,
void ShaderManager::init_xyz_transforms()
{
- /* Default to ITU-BT.709 in case no appropriate transform found. */
+ /* Default to ITU-BT.709 in case no appropriate transform found.
+ * Note XYZ here is defined as having a D65 white point. */
xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
xyz_to_g = make_float3(-0.9692660f, 1.8760108f, 0.0415560f);
xyz_to_b = make_float3(0.0556434f, -0.2040259f, 1.0572252f);
@@ -848,24 +849,27 @@ void ShaderManager::init_xyz_transforms()
if (config->hasRole("aces_interchange")) {
/* Standard OpenColorIO role, defined as ACES2065-1. */
- const Transform xyz_to_aces = make_transform(1.0498110175f,
- 0.0f,
- -0.0000974845f,
- 0.0f,
- -0.4959030231f,
- 1.3733130458f,
- 0.0982400361f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.9912520182f,
- 0.0f);
+ const Transform xyz_E_to_aces = make_transform(1.0498110175f,
+ 0.0f,
+ -0.0000974845f,
+ 0.0f,
+ -0.4959030231f,
+ 1.3733130458f,
+ 0.0982400361f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.9912520182f,
+ 0.0f);
+ const Transform xyz_D65_to_E = make_transform(
+ 1.0521111f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9184170f, 0.0f);
+
Transform aces_to_rgb;
if (!to_scene_linear_transform(config, "aces_interchange", aces_to_rgb)) {
return;
}
- xyz_to_rgb = aces_to_rgb * xyz_to_aces;
+ xyz_to_rgb = aces_to_rgb * xyz_E_to_aces * xyz_D65_to_E;
}
else if (config->hasRole("XYZ")) {
/* Custom role used before the standard existed. */
diff --git a/intern/cycles/render/volume.cpp b/intern/cycles/render/volume.cpp
index a1bd16798fb..358ef71d501 100644
--- a/intern/cycles/render/volume.cpp
+++ b/intern/cycles/render/volume.cpp
@@ -36,7 +36,7 @@ CCL_NAMESPACE_BEGIN
NODE_DEFINE(Volume)
{
- NodeType *type = NodeType::add("volume", create, NodeType::NONE, Mesh::node_type);
+ NodeType *type = NodeType::add("volume", create, NodeType::NONE, Mesh::get_node_type());
SOCKET_FLOAT(clipping, "Clipping", 0.001f);
SOCKET_FLOAT(step_size, "Step Size", 0.0f);
@@ -45,7 +45,7 @@ NODE_DEFINE(Volume)
return type;
}
-Volume::Volume() : Mesh(node_type, Geometry::VOLUME)
+Volume::Volume() : Mesh(get_node_type(), Geometry::VOLUME)
{
clipping = 0.001f;
step_size = 0.0f;
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index ab76b78e6df..687173ded09 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -278,7 +278,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
#ifdef GHOST_WAIT_FOR_VSYNC
{
GLint swapInt = 1;
- /* wait for vsync, to avoid tearing artifacts */
+ /* Wait for vertical-sync, to avoid tearing artifacts. */
[m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
}
#endif
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index f42d4af109a..9c28449a4e5 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -80,7 +80,7 @@ static GHOST_TButtonMask convertButton(int button)
}
/**
- * Converts Mac rawkey codes (same for Cocoa & Carbon)
+ * Converts Mac raw-key codes (same for Cocoa & Carbon)
* into GHOST key codes
* \param rawCode: The raw physical key code
* \param recvChar: the character ignoring modifiers (except for shift)
@@ -386,13 +386,11 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
- (id)init
{
self = [super init];
- if (self) {
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(windowWillClose:)
- name:NSWindowWillCloseNotification
- object:nil];
- }
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(windowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:nil];
return self;
}
@@ -563,92 +561,96 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
SetFrontProcess(&psn);
}*/
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [NSApplication sharedApplication]; // initializes NSApp
-
- if ([NSApp mainMenu] == nil) {
- NSMenu *mainMenubar = [[NSMenu alloc] init];
- NSMenuItem *menuItem;
- NSMenu *windowMenu;
- NSMenu *appMenu;
-
- // Create the application menu
- appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
-
- [appMenu addItemWithTitle:@"About Blender"
- action:@selector(orderFrontStandardAboutPanel:)
- keyEquivalent:@""];
- [appMenu addItem:[NSMenuItem separatorItem]];
-
- menuItem = [appMenu addItemWithTitle:@"Hide Blender"
- action:@selector(hide:)
- keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
-
- menuItem = [appMenu addItemWithTitle:@"Hide Others"
- action:@selector(hideOtherApplications:)
- keyEquivalent:@"h"];
- [menuItem
- setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
-
- [appMenu addItemWithTitle:@"Show All"
- action:@selector(unhideAllApplications:)
- keyEquivalent:@""];
-
- menuItem = [appMenu addItemWithTitle:@"Quit Blender"
- action:@selector(terminate:)
- keyEquivalent:@"q"];
- [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
-
- menuItem = [[NSMenuItem alloc] init];
- [menuItem setSubmenu:appMenu];
-
- [mainMenubar addItem:menuItem];
- [menuItem release];
- [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; // Needed for 10.5
- [appMenu release];
-
- // Create the window menu
- windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-
- menuItem = [windowMenu addItemWithTitle:@"Minimize"
- action:@selector(performMiniaturize:)
- keyEquivalent:@"m"];
- [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
-
- [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
-
- menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen"
- action:@selector(toggleFullScreen:)
- keyEquivalent:@"f"];
- [menuItem
- setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
-
- menuItem = [windowMenu addItemWithTitle:@"Close"
- action:@selector(performClose:)
- keyEquivalent:@"w"];
- [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
-
- menuItem = [[NSMenuItem alloc] init];
- [menuItem setSubmenu:windowMenu];
-
- [mainMenubar addItem:menuItem];
- [menuItem release];
-
- [NSApp setMainMenu:mainMenubar];
- [NSApp setWindowsMenu:windowMenu];
- [windowMenu release];
- }
+ @autoreleasepool {
+ [NSApplication sharedApplication]; // initializes NSApp
+
+ if ([NSApp mainMenu] == nil) {
+ NSMenu *mainMenubar = [[NSMenu alloc] init];
+ NSMenuItem *menuItem;
+ NSMenu *windowMenu;
+ NSMenu *appMenu;
+
+ // Create the application menu
+ appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
+
+ [appMenu addItemWithTitle:@"About Blender"
+ action:@selector(orderFrontStandardAboutPanel:)
+ keyEquivalent:@""];
+ [appMenu addItem:[NSMenuItem separatorItem]];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide Blender"
+ action:@selector(hide:)
+ keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide Others"
+ action:@selector(hideOtherApplications:)
+ keyEquivalent:@"h"];
+ [menuItem
+ setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
+
+ [appMenu addItemWithTitle:@"Show All"
+ action:@selector(unhideAllApplications:)
+ keyEquivalent:@""];
+
+ menuItem = [appMenu addItemWithTitle:@"Quit Blender"
+ action:@selector(terminate:)
+ keyEquivalent:@"q"];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:appMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+ [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; // Needed for 10.5
+ [appMenu release];
+
+ // Create the window menu
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ menuItem = [windowMenu addItemWithTitle:@"Minimize"
+ action:@selector(performMiniaturize:)
+ keyEquivalent:@"m"];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
+
+ [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
+
+ menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen"
+ action:@selector(toggleFullScreen:)
+ keyEquivalent:@"f"];
+ [menuItem
+ setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
+
+ menuItem = [windowMenu addItemWithTitle:@"Close"
+ action:@selector(performClose:)
+ keyEquivalent:@"w"];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:windowMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+
+ [NSApp setMainMenu:mainMenubar];
+ [NSApp setWindowsMenu:windowMenu];
+ [windowMenu release];
+ }
- if ([NSApp delegate] == nil) {
- CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
- [appDelegate setSystemCocoa:this];
- [NSApp setDelegate:appDelegate];
- }
+ if ([NSApp delegate] == nil) {
+ CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
+ [appDelegate setSystemCocoa:this];
+ [NSApp setDelegate:appDelegate];
+ }
- [NSApp finishLaunching];
+ // AppKit provides automatic window tabbing. Blender is a single-tabbed application
+ // without a macOS tab bar, and should explicitly opt-out of this. This is also
+ // controlled by the macOS user default #NSWindowTabbingEnabled.
+ NSWindow.allowsAutomaticWindowTabbing = NO;
- [pool drain];
+ [NSApp finishLaunching];
+ }
}
return success;
}
@@ -671,30 +673,26 @@ GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const
{
// Note that OS X supports monitor hot plug
// We do not support multiple monitors at the moment
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- GHOST_TUns8 count = [[NSScreen screens] count];
-
- [pool drain];
- return count;
+ @autoreleasepool {
+ return NSScreen.screens.count;
+ }
}
void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- // Get visible frame, that is frame excluding dock and top menu bar
- NSRect frame = [[NSScreen mainScreen] visibleFrame];
-
- // Returns max window contents (excluding title bar...)
- NSRect contentRect = [NSWindow
- contentRectForFrameRect:frame
- styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
- NSWindowStyleMaskMiniaturizable)];
-
- width = contentRect.size.width;
- height = contentRect.size.height;
-
- [pool drain];
+ @autoreleasepool {
+ // Get visible frame, that is frame excluding dock and top menu bar
+ NSRect frame = [[NSScreen mainScreen] visibleFrame];
+
+ // Returns max window contents (excluding title bar...)
+ NSRect contentRect = [NSWindow
+ contentRectForFrameRect:frame
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable)];
+
+ width = contentRect.size.width;
+ height = contentRect.size.height;
+ }
}
void GHOST_SystemCocoa::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
@@ -715,53 +713,52 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
const bool is_dialog,
const GHOST_IWindow *parentWindow)
{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GHOST_IWindow *window = NULL;
-
- // Get the available rect for including window contents
- NSRect frame = [[NSScreen mainScreen] visibleFrame];
- NSRect contentRect = [NSWindow
- contentRectForFrameRect:frame
- styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
- NSWindowStyleMaskMiniaturizable)];
-
- GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
-
- // Ensures window top left is inside this available rect
- left = left > contentRect.origin.x ? left : contentRect.origin.x;
- // Add contentRect.origin.y to respect docksize
- bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y;
-
- window = new GHOST_WindowCocoa(this,
- title,
- left,
- bottom,
- width,
- height,
- state,
- type,
- glSettings.flags & GHOST_glStereoVisual,
- glSettings.flags & GHOST_glDebugContext,
- is_dialog,
- (GHOST_WindowCocoa *)parentWindow);
-
- if (window->getValid()) {
- // Store the pointer to the window
- GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
- m_windowManager->addWindow(window);
- m_windowManager->setActiveWindow(window);
- /* Need to tell window manager the new window is the active one
- * (Cocoa does not send the event activate upon window creation). */
- pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window));
- pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
- }
- else {
- GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
- delete window;
- window = NULL;
+ @autoreleasepool {
+
+ // Get the available rect for including window contents
+ NSRect frame = [[NSScreen mainScreen] visibleFrame];
+ NSRect contentRect = [NSWindow
+ contentRectForFrameRect:frame
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable)];
+
+ GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
+
+ // Ensures window top left is inside this available rect
+ left = left > contentRect.origin.x ? left : contentRect.origin.x;
+ // Add contentRect.origin.y to respect docksize
+ bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y;
+
+ window = new GHOST_WindowCocoa(this,
+ title,
+ left,
+ bottom,
+ width,
+ height,
+ state,
+ type,
+ glSettings.flags & GHOST_glStereoVisual,
+ glSettings.flags & GHOST_glDebugContext,
+ is_dialog,
+ (GHOST_WindowCocoa *)parentWindow);
+
+ if (window->getValid()) {
+ // Store the pointer to the window
+ GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
+ m_windowManager->addWindow(window);
+ m_windowManager->setActiveWindow(window);
+ /* Need to tell window manager the new window is the active one
+ * (Cocoa does not send the event activate upon window creation). */
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window));
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
+ }
+ else {
+ GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
+ delete window;
+ window = NULL;
+ }
}
-
- [pool drain];
return window;
}
@@ -836,29 +833,28 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T
if (!window)
return GHOST_kFailure;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSScreen *windowScreen = window->getScreen();
- NSRect screenRect = [windowScreen frame];
+ @autoreleasepool {
+ NSScreen *windowScreen = window->getScreen();
+ NSRect screenRect = [windowScreen frame];
- // Set position relative to current screen
- xf -= screenRect.origin.x;
- yf -= screenRect.origin.y;
+ // Set position relative to current screen
+ xf -= screenRect.origin.x;
+ yf -= screenRect.origin.y;
- // Quartz Display Services uses the old coordinates (top left origin)
- yf = screenRect.size.height - yf;
+ // Quartz Display Services uses the old coordinates (top left origin)
+ yf = screenRect.size.height - yf;
- CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription]
- objectForKey:@"NSScreenNumber"] unsignedIntValue],
- CGPointMake(xf, yf));
+ CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription]
+ objectForKey:@"NSScreenNumber"] unsignedIntValue],
+ CGPointMake(xf, yf));
- // See https://stackoverflow.com/a/17559012. By default, hardware events
- // will be suppressed for 500ms after a synthetic mouse event. For unknown
- // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work,
- // however calling CGAssociateMouseAndMouseCursorPosition also removes the
- // delay, even if this is undocumented.
- CGAssociateMouseAndMouseCursorPosition(true);
-
- [pool drain];
+ // See https://stackoverflow.com/a/17559012. By default, hardware events
+ // will be suppressed for 500ms after a synthetic mouse event. For unknown
+ // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work,
+ // however calling CGAssociateMouseAndMouseCursorPosition also removes the
+ // delay, even if this is undocumented.
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
return GHOST_kSuccess;
}
@@ -923,42 +919,40 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
}
#endif
do {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- event = [NSApp nextEventMatchingMask:NSEventMaskAny
- untilDate:[NSDate distantPast]
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
- if (event == nil) {
- [pool drain];
- break;
- }
+ @autoreleasepool {
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event == nil) {
+ break;
+ }
- anyProcessed = true;
+ anyProcessed = true;
- // Send event to NSApp to ensure Mac wide events are handled,
- // this will send events to CocoaWindow which will call back
- // to handleKeyEvent, handleMouseEvent and handleTabletEvent
+ // Send event to NSApp to ensure Mac wide events are handled,
+ // this will send events to CocoaWindow which will call back
+ // to handleKeyEvent, handleMouseEvent and handleTabletEvent
- // There is on special exception for ctrl+(shift)+tab. We do not
- // get keyDown events delivered to the view because they are
- // special hotkeys to switch between views, so override directly
+ // There is on special exception for ctrl+(shift)+tab. We do not
+ // get keyDown events delivered to the view because they are
+ // special hotkeys to switch between views, so override directly
- if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
- ([event modifierFlags] & NSEventModifierFlagControl)) {
- handleKeyEvent(event);
- }
- else {
- // For some reason NSApp is swallowing the key up events when modifier
- // key is pressed, even if there seems to be no apparent reason to do
- // so, as a workaround we always handle these up events.
- if ([event type] == NSEventTypeKeyUp &&
- ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
+ if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
+ ([event modifierFlags] & NSEventModifierFlagControl)) {
handleKeyEvent(event);
-
- [NSApp sendEvent:event];
+ }
+ else {
+ // For some reason NSApp is swallowing the key up events when modifier
+ // key is pressed, even if there seems to be no apparent reason to do
+ // so, as a workaround we always handle these up events.
+ if ([event type] == NSEventTypeKeyUp &&
+ ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
+ handleKeyEvent(event);
+
+ [NSApp sendEvent:event];
+ }
}
-
- [pool drain];
} while (event != nil);
#if 0
} while (waitForEvent && !anyProcessed); // Needed only for timer implementation
@@ -1672,10 +1666,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
NSEventPhase momentumPhase = NSEventPhaseNone;
NSEventPhase phase = NSEventPhaseNone;
- if ([event respondsToSelector:@selector(momentumPhase)])
- momentumPhase = [event momentumPhase];
- if ([event respondsToSelector:@selector(phase)])
- phase = [event phase];
+ momentumPhase = [event momentumPhase];
+ phase = [event phase];
/* when pressing a key while momentum scrolling continues after
* lifting fingers off the trackpad, the action can unexpectedly
@@ -1948,78 +1940,48 @@ GHOST_TUns8 *GHOST_SystemCocoa::getClipboard(bool selection) const
GHOST_TUns8 *temp_buff;
size_t pastedTextSize;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
-
- if (pasteBoard == nil) {
- [pool drain];
- return NULL;
- }
-
- NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
+ @autoreleasepool {
- NSString *bestType = [[NSPasteboard generalPasteboard] availableTypeFromArray:supportedTypes];
-
- if (bestType == nil) {
- [pool drain];
- return NULL;
- }
+ NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
- NSString *textPasted = [pasteBoard stringForType:NSStringPboardType];
+ NSString *textPasted = [pasteBoard stringForType:NSStringPboardType];
- if (textPasted == nil) {
- [pool drain];
- return NULL;
- }
+ if (textPasted == nil) {
+ return NULL;
+ }
- pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+ pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
- temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1);
+ temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1);
- if (temp_buff == NULL) {
- [pool drain];
- return NULL;
- }
-
- strncpy(
- (char *)temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
+ if (temp_buff == NULL) {
+ return NULL;
+ }
- temp_buff[pastedTextSize] = '\0';
+ strncpy(
+ (char *)temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
- [pool drain];
+ temp_buff[pastedTextSize] = '\0';
- if (temp_buff) {
- return temp_buff;
- }
- else {
- return NULL;
+ if (temp_buff) {
+ return temp_buff;
+ }
+ else {
+ return NULL;
+ }
}
}
void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
{
- NSString *textToCopy;
-
if (selection)
return; // for copying the selection, used on X11
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ @autoreleasepool {
- NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
-
- if (pasteBoard == nil) {
- [pool drain];
- return;
+ NSPasteboard *pasteBoard = NSPasteboard.generalPasteboard;
+ [pasteBoard declareTypes:@[ NSStringPboardType ] owner:nil];
+ NSString *textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
+ [pasteBoard setString:textToCopy forType:NSStringPboardType];
}
-
- NSArray *supportedTypes = [NSArray arrayWithObject:NSStringPboardType];
-
- [pasteBoard declareTypes:supportedTypes owner:nil];
-
- textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
-
- [pasteBoard setString:textToCopy forType:NSStringPboardType];
-
- [pool drain];
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index a7e325bc9e1..ed5e945f69e 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -34,9 +34,9 @@
#ifdef WITH_X11_XINPUT
# include <X11/extensions/XInput.h>
-/* Disable xinput warp, currently not implemented by Xorg for multi-head display.
- * (see comment in xserver "Xi/xiwarppointer.c" -> "FIXME: panoramix stuff is missing" ~ v1.13.4)
- * If this is supported we can add back xinput for warping (fixing T48901).
+/* Disable XINPUT warp, currently not implemented by Xorg for multi-head display.
+ * (see comment in XSERVER `Xi/xiwarppointer.c` -> `FIXME: panoramix stuff is missing` ~ v1.13.4)
+ * If this is supported we can add back XINPUT for warping (fixing T48901).
* For now disable (see T50383). */
// # define USE_X11_XINPUT_WARP
#endif
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 73927317b24..add7962d924 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -336,11 +336,6 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
backing:NSBackingStoreBuffered
defer:NO];
- if (m_window == nil) {
- [pool drain];
- return;
- }
-
[m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
// Forbid to resize the window below the blender defined minimum one
diff --git a/intern/ghost/intern/GHOST_WindowViewCocoa.h b/intern/ghost/intern/GHOST_WindowViewCocoa.h
index 14c70382916..f47e02704b2 100644
--- a/intern/ghost/intern/GHOST_WindowViewCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowViewCocoa.h
@@ -253,7 +253,7 @@
- (NSAttributedString *)attributedSubstringFromRange:(NSRange)range
{
- return [NSAttributedString new]; // XXX does this leak?
+ return [[[NSAttributedString alloc] init] autorelease];
}
- (NSRange)markedRange
@@ -284,7 +284,7 @@
- (NSArray *)validAttributesForMarkedText
{
- return [NSArray array]; // XXX does this leak?
+ return [NSArray array];
}
@end
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index ad5643fcd89..de4e77ffc24 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -92,16 +92,11 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
{
wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
RECT win_rect = {left, top, (long)(left + width), (long)(top + height)};
- RECT parent_rect = {0, 0, 0, 0};
// Initialize tablet variables
memset(&m_wintab, 0, sizeof(m_wintab));
m_tabletData = GHOST_TABLET_DATA_NONE;
- if (parentwindow) {
- GetWindowRect(m_parentWindowHwnd, &parent_rect);
- }
-
DWORD style = parentwindow ?
WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX :
WS_OVERLAPPEDWINDOW;
@@ -124,9 +119,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
MONITORINFOEX monitor;
monitor.cbSize = sizeof(MONITORINFOEX);
monitor.dwFlags = 0;
- GetMonitorInfo(
- MonitorFromRect(parentwindow ? &parent_rect : &win_rect, MONITOR_DEFAULTTONEAREST),
- &monitor);
+ GetMonitorInfo(MonitorFromRect(&win_rect, MONITOR_DEFAULTTONEAREST), &monitor);
/* Adjust our requested size to allow for caption and borders and constrain to monitor. */
AdjustWindowRectEx(&win_rect, WS_CAPTION, FALSE, 0);
@@ -1200,7 +1193,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap
GHOST_TUns32 fullBitRow, fullMaskRow;
int x, y, cols;
- cols = sizeX / 8; /* Number of whole bytes per row (width of bm/mask). */
+ cols = sizeX / 8; /* Number of whole bytes per row (width of bitmap/mask). */
if (sizeX % 8)
cols++;
diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt
index b47565b8ef9..88c6e7ca2c5 100644
--- a/intern/guardedalloc/CMakeLists.txt
+++ b/intern/guardedalloc/CMakeLists.txt
@@ -77,6 +77,7 @@ if(WITH_GTESTS)
set(TEST_SRC
tests/guardedalloc_alignment_test.cc
tests/guardedalloc_overflow_test.cc
+ tests/guardedalloc_test_base.h
)
set(TEST_INC
../../source/blender/blenlib
diff --git a/intern/libmv/.clang-format b/intern/libmv/.clang-format
index 9d159247d51..fae0530c572 100644
--- a/intern/libmv/.clang-format
+++ b/intern/libmv/.clang-format
@@ -1,2 +1,34 @@
-DisableFormat: true
-SortIncludes: false
+BasedOnStyle: Google
+
+ColumnLimit: 80
+
+Standard: Cpp11
+
+# Indent nested preprocessor.
+# #ifdef Foo
+# # include <nested>
+# #endif
+IndentPPDirectives: AfterHash
+
+# For the cases when namespace is closing with a wrong comment
+FixNamespaceComments: true
+
+AllowShortFunctionsOnASingleLine: InlineOnly
+AllowShortBlocksOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: true
+
+# No bin packing, every argument is on its own line.
+BinPackArguments: false
+BinPackParameters: false
+
+# Ensure pointer alignment.
+# ObjectType* object;
+PointerAlignment: Left
+DerivePointerAlignment: false
+
+AlignEscapedNewlines: Right
+
+IncludeBlocks: Preserve
+SortIncludes: true
diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc
index 7000a422de8..b7110957b15 100644
--- a/intern/libmv/intern/autotrack.cc
+++ b/intern/libmv/intern/autotrack.cc
@@ -22,15 +22,15 @@
#include "intern/utildefines.h"
#include "libmv/autotrack/autotrack.h"
+using libmv::TrackRegionOptions;
+using libmv::TrackRegionResult;
using mv::AutoTrack;
using mv::FrameAccessor;
using mv::Marker;
-using libmv::TrackRegionOptions;
-using libmv::TrackRegionResult;
-libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor) {
- return (libmv_AutoTrack*) LIBMV_OBJECT_NEW(AutoTrack,
- (FrameAccessor*) frame_accessor);
+libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* frame_accessor) {
+ return (libmv_AutoTrack*)LIBMV_OBJECT_NEW(AutoTrack,
+ (FrameAccessor*)frame_accessor);
}
void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) {
@@ -39,7 +39,7 @@ void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) {
void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack,
const libmv_AutoTrackOptions* options) {
- AutoTrack *autotrack = ((AutoTrack*) libmv_autotrack);
+ AutoTrack* autotrack = ((AutoTrack*)libmv_autotrack);
libmv_configureTrackRegionOptions(options->track_region,
&autotrack->options.track_region);
@@ -51,18 +51,15 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack,
int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack,
const libmv_TrackRegionOptions* libmv_options,
- libmv_Marker *libmv_tracked_marker,
+ libmv_Marker* libmv_tracked_marker,
libmv_TrackRegionResult* libmv_result) {
-
Marker tracked_marker;
TrackRegionOptions options;
TrackRegionResult result;
libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker);
- libmv_configureTrackRegionOptions(*libmv_options,
- &options);
- bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker,
- &result,
- &options));
+ libmv_configureTrackRegionOptions(*libmv_options, &options);
+ bool ok = (((AutoTrack*)libmv_autotrack)
+ ->TrackMarker(&tracked_marker, &result, &options));
libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker);
libmv_regionTrackergetResult(result, libmv_result);
return ok && result.is_usable();
@@ -72,7 +69,7 @@ void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack,
const libmv_Marker* libmv_marker) {
Marker marker;
libmv_apiMarkerToMarker(*libmv_marker, &marker);
- ((AutoTrack*) libmv_autotrack)->AddMarker(marker);
+ ((AutoTrack*)libmv_autotrack)->AddMarker(marker);
}
void libmv_autoTrackSetMarkers(libmv_AutoTrack* libmv_autotrack,
@@ -87,19 +84,17 @@ void libmv_autoTrackSetMarkers(libmv_AutoTrack* libmv_autotrack,
for (size_t i = 0; i < num_markers; ++i) {
libmv_apiMarkerToMarker(libmv_marker[i], &markers[i]);
}
- ((AutoTrack*) libmv_autotrack)->SetMarkers(&markers);
+ ((AutoTrack*)libmv_autotrack)->SetMarkers(&markers);
}
int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack,
int clip,
int frame,
int track,
- libmv_Marker *libmv_marker) {
+ libmv_Marker* libmv_marker) {
Marker marker;
- int ok = ((AutoTrack*) libmv_autotrack)->GetMarker(clip,
- frame,
- track,
- &marker);
+ int ok =
+ ((AutoTrack*)libmv_autotrack)->GetMarker(clip, frame, track, &marker);
if (ok) {
libmv_markerToApiMarker(marker, libmv_marker);
}
diff --git a/intern/libmv/intern/autotrack.h b/intern/libmv/intern/autotrack.h
index 6b49a6908e1..3887983814b 100644
--- a/intern/libmv/intern/autotrack.h
+++ b/intern/libmv/intern/autotrack.h
@@ -21,9 +21,9 @@
#define LIBMV_C_API_AUTOTRACK_H_
#include "intern/frame_accessor.h"
-#include "intern/tracksN.h"
-#include "intern/track_region.h"
#include "intern/region.h"
+#include "intern/track_region.h"
+#include "intern/tracksN.h"
#ifdef __cplusplus
extern "C" {
@@ -36,7 +36,7 @@ typedef struct libmv_AutoTrackOptions {
libmv_Region search_region;
} libmv_AutoTrackOptions;
-libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor);
+libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* frame_accessor);
void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack);
@@ -45,7 +45,7 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack,
int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack,
const libmv_TrackRegionOptions* libmv_options,
- libmv_Marker *libmv_tracker_marker,
+ libmv_Marker* libmv_tracker_marker,
libmv_TrackRegionResult* libmv_result);
void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack,
@@ -59,7 +59,7 @@ int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack,
int clip,
int frame,
int track,
- libmv_Marker *libmv_marker);
+ libmv_Marker* libmv_marker);
#ifdef __cplusplus
}
diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc
index 628637e12cc..243b26d9fb3 100644
--- a/intern/libmv/intern/camera_intrinsics.cc
+++ b/intern/libmv/intern/camera_intrinsics.cc
@@ -21,62 +21,56 @@
#include "intern/utildefines.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
+using libmv::BrownCameraIntrinsics;
using libmv::CameraIntrinsics;
using libmv::DivisionCameraIntrinsics;
-using libmv::PolynomialCameraIntrinsics;
using libmv::NukeCameraIntrinsics;
-using libmv::BrownCameraIntrinsics;
+using libmv::PolynomialCameraIntrinsics;
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
+libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew(
const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) {
- CameraIntrinsics *camera_intrinsics =
- libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
- return (libmv_CameraIntrinsics *) camera_intrinsics;
+ CameraIntrinsics* camera_intrinsics =
+ libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
+ return (libmv_CameraIntrinsics*)camera_intrinsics;
}
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
+libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy(
const libmv_CameraIntrinsics* libmv_intrinsics) {
- const CameraIntrinsics *orig_intrinsics =
- (const CameraIntrinsics *) libmv_intrinsics;
+ const CameraIntrinsics* orig_intrinsics =
+ (const CameraIntrinsics*)libmv_intrinsics;
- CameraIntrinsics *new_intrinsics = NULL;
+ CameraIntrinsics* new_intrinsics = NULL;
switch (orig_intrinsics->GetDistortionModelType()) {
- case libmv::DISTORTION_MODEL_POLYNOMIAL:
- {
- const PolynomialCameraIntrinsics *polynomial_intrinsics =
+ case libmv::DISTORTION_MODEL_POLYNOMIAL: {
+ const PolynomialCameraIntrinsics* polynomial_intrinsics =
static_cast<const PolynomialCameraIntrinsics*>(orig_intrinsics);
- new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics,
- *polynomial_intrinsics);
- break;
- }
- case libmv::DISTORTION_MODEL_DIVISION:
- {
- const DivisionCameraIntrinsics *division_intrinsics =
+ new_intrinsics =
+ LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, *polynomial_intrinsics);
+ break;
+ }
+ case libmv::DISTORTION_MODEL_DIVISION: {
+ const DivisionCameraIntrinsics* division_intrinsics =
static_cast<const DivisionCameraIntrinsics*>(orig_intrinsics);
- new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics,
- *division_intrinsics);
- break;
- }
- case libmv::DISTORTION_MODEL_NUKE:
- {
- const NukeCameraIntrinsics *nuke_intrinsics =
+ new_intrinsics =
+ LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, *division_intrinsics);
+ break;
+ }
+ case libmv::DISTORTION_MODEL_NUKE: {
+ const NukeCameraIntrinsics* nuke_intrinsics =
static_cast<const NukeCameraIntrinsics*>(orig_intrinsics);
- new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics,
- *nuke_intrinsics);
- break;
- }
- case libmv::DISTORTION_MODEL_BROWN:
- {
- const BrownCameraIntrinsics *brown_intrinsics =
+ new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics, *nuke_intrinsics);
+ break;
+ }
+ case libmv::DISTORTION_MODEL_BROWN: {
+ const BrownCameraIntrinsics* brown_intrinsics =
static_cast<const BrownCameraIntrinsics*>(orig_intrinsics);
- new_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics,
- *brown_intrinsics);
- break;
- }
- default:
- assert(!"Unknown distortion model");
+ new_intrinsics =
+ LIBMV_OBJECT_NEW(BrownCameraIntrinsics, *brown_intrinsics);
+ break;
+ }
+ default: assert(!"Unknown distortion model");
}
- return (libmv_CameraIntrinsics *) new_intrinsics;
+ return (libmv_CameraIntrinsics*)new_intrinsics;
}
void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) {
@@ -86,7 +80,7 @@ void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) {
void libmv_cameraIntrinsicsUpdate(
const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
libmv_CameraIntrinsics* libmv_intrinsics) {
- CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics;
double focal_length = libmv_camera_intrinsics_options->focal_length;
double principal_x = libmv_camera_intrinsics_options->principal_point_x;
@@ -115,191 +109,173 @@ void libmv_cameraIntrinsicsUpdate(
}
switch (libmv_camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- {
- assert(camera_intrinsics->GetDistortionModelType() ==
- libmv::DISTORTION_MODEL_POLYNOMIAL);
-
- PolynomialCameraIntrinsics *polynomial_intrinsics =
- (PolynomialCameraIntrinsics *) camera_intrinsics;
-
- double k1 = libmv_camera_intrinsics_options->polynomial_k1;
- double k2 = libmv_camera_intrinsics_options->polynomial_k2;
- double k3 = libmv_camera_intrinsics_options->polynomial_k3;
-
- if (polynomial_intrinsics->k1() != k1 ||
- polynomial_intrinsics->k2() != k2 ||
- polynomial_intrinsics->k3() != k3) {
- polynomial_intrinsics->SetRadialDistortion(k1, k2, k3);
- }
- break;
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL: {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_POLYNOMIAL);
+
+ PolynomialCameraIntrinsics* polynomial_intrinsics =
+ (PolynomialCameraIntrinsics*)camera_intrinsics;
+
+ double k1 = libmv_camera_intrinsics_options->polynomial_k1;
+ double k2 = libmv_camera_intrinsics_options->polynomial_k2;
+ double k3 = libmv_camera_intrinsics_options->polynomial_k3;
+
+ if (polynomial_intrinsics->k1() != k1 ||
+ polynomial_intrinsics->k2() != k2 ||
+ polynomial_intrinsics->k3() != k3) {
+ polynomial_intrinsics->SetRadialDistortion(k1, k2, k3);
}
+ break;
+ }
- case LIBMV_DISTORTION_MODEL_DIVISION:
- {
- assert(camera_intrinsics->GetDistortionModelType() ==
- libmv::DISTORTION_MODEL_DIVISION);
+ case LIBMV_DISTORTION_MODEL_DIVISION: {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_DIVISION);
- DivisionCameraIntrinsics *division_intrinsics =
- (DivisionCameraIntrinsics *) camera_intrinsics;
+ DivisionCameraIntrinsics* division_intrinsics =
+ (DivisionCameraIntrinsics*)camera_intrinsics;
- double k1 = libmv_camera_intrinsics_options->division_k1;
- double k2 = libmv_camera_intrinsics_options->division_k2;
+ double k1 = libmv_camera_intrinsics_options->division_k1;
+ double k2 = libmv_camera_intrinsics_options->division_k2;
- if (division_intrinsics->k1() != k1 ||
- division_intrinsics->k2() != k2) {
- division_intrinsics->SetDistortion(k1, k2);
- }
+ if (division_intrinsics->k1() != k1 || division_intrinsics->k2() != k2) {
+ division_intrinsics->SetDistortion(k1, k2);
+ }
- break;
+ break;
+ }
+
+ case LIBMV_DISTORTION_MODEL_NUKE: {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_NUKE);
+
+ NukeCameraIntrinsics* nuke_intrinsics =
+ (NukeCameraIntrinsics*)camera_intrinsics;
+
+ double k1 = libmv_camera_intrinsics_options->nuke_k1;
+ double k2 = libmv_camera_intrinsics_options->nuke_k2;
+
+ if (nuke_intrinsics->k1() != k1 || nuke_intrinsics->k2() != k2) {
+ nuke_intrinsics->SetDistortion(k1, k2);
}
- case LIBMV_DISTORTION_MODEL_NUKE:
- {
- assert(camera_intrinsics->GetDistortionModelType() ==
- libmv::DISTORTION_MODEL_NUKE);
+ break;
+ }
- NukeCameraIntrinsics *nuke_intrinsics =
- (NukeCameraIntrinsics *) camera_intrinsics;
+ case LIBMV_DISTORTION_MODEL_BROWN: {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_BROWN);
- double k1 = libmv_camera_intrinsics_options->nuke_k1;
- double k2 = libmv_camera_intrinsics_options->nuke_k2;
+ BrownCameraIntrinsics* brown_intrinsics =
+ (BrownCameraIntrinsics*)camera_intrinsics;
- if (nuke_intrinsics->k1() != k1 ||
- nuke_intrinsics->k2() != k2) {
- nuke_intrinsics->SetDistortion(k1, k2);
- }
+ double k1 = libmv_camera_intrinsics_options->brown_k1;
+ double k2 = libmv_camera_intrinsics_options->brown_k2;
+ double k3 = libmv_camera_intrinsics_options->brown_k3;
+ double k4 = libmv_camera_intrinsics_options->brown_k4;
- break;
+ if (brown_intrinsics->k1() != k1 || brown_intrinsics->k2() != k2 ||
+ brown_intrinsics->k3() != k3 || brown_intrinsics->k4() != k4) {
+ brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4);
}
- case LIBMV_DISTORTION_MODEL_BROWN:
- {
- assert(camera_intrinsics->GetDistortionModelType() ==
- libmv::DISTORTION_MODEL_BROWN);
-
- BrownCameraIntrinsics *brown_intrinsics =
- (BrownCameraIntrinsics *) camera_intrinsics;
-
- double k1 = libmv_camera_intrinsics_options->brown_k1;
- double k2 = libmv_camera_intrinsics_options->brown_k2;
- double k3 = libmv_camera_intrinsics_options->brown_k3;
- double k4 = libmv_camera_intrinsics_options->brown_k4;
-
- if (brown_intrinsics->k1() != k1 ||
- brown_intrinsics->k2() != k2 ||
- brown_intrinsics->k3() != k3 ||
- brown_intrinsics->k4() != k4) {
- brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4);
- }
-
- double p1 = libmv_camera_intrinsics_options->brown_p1;
- double p2 = libmv_camera_intrinsics_options->brown_p2;
-
- if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) {
- brown_intrinsics->SetTangentialDistortion(p1, p2);
- }
- break;
+ double p1 = libmv_camera_intrinsics_options->brown_p1;
+ double p2 = libmv_camera_intrinsics_options->brown_p2;
+
+ if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) {
+ brown_intrinsics->SetTangentialDistortion(p1, p2);
}
+ break;
+ }
- default:
- assert(!"Unknown distortion model");
+ default: assert(!"Unknown distortion model");
}
}
void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics,
int threads) {
- CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics;
camera_intrinsics->SetThreads(threads);
}
void libmv_cameraIntrinsicsExtractOptions(
const libmv_CameraIntrinsics* libmv_intrinsics,
libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
- const CameraIntrinsics *camera_intrinsics =
- (const CameraIntrinsics *) libmv_intrinsics;
+ const CameraIntrinsics* camera_intrinsics =
+ (const CameraIntrinsics*)libmv_intrinsics;
// Fill in options which are common for all distortion models.
camera_intrinsics_options->focal_length = camera_intrinsics->focal_length();
camera_intrinsics_options->principal_point_x =
- camera_intrinsics->principal_point_x();
+ camera_intrinsics->principal_point_x();
camera_intrinsics_options->principal_point_y =
- camera_intrinsics->principal_point_y();
+ camera_intrinsics->principal_point_y();
camera_intrinsics_options->image_width = camera_intrinsics->image_width();
camera_intrinsics_options->image_height = camera_intrinsics->image_height();
switch (camera_intrinsics->GetDistortionModelType()) {
- case libmv::DISTORTION_MODEL_POLYNOMIAL:
- {
- const PolynomialCameraIntrinsics *polynomial_intrinsics =
- static_cast<const PolynomialCameraIntrinsics *>(camera_intrinsics);
- camera_intrinsics_options->distortion_model =
+ case libmv::DISTORTION_MODEL_POLYNOMIAL: {
+ const PolynomialCameraIntrinsics* polynomial_intrinsics =
+ static_cast<const PolynomialCameraIntrinsics*>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
LIBMV_DISTORTION_MODEL_POLYNOMIAL;
- camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1();
- camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2();
- camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3();
- camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1();
- camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2();
- break;
- }
+ camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1();
+ camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2();
+ camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3();
+ camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1();
+ camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2();
+ break;
+ }
- case libmv::DISTORTION_MODEL_DIVISION:
- {
- const DivisionCameraIntrinsics *division_intrinsics =
- static_cast<const DivisionCameraIntrinsics *>(camera_intrinsics);
- camera_intrinsics_options->distortion_model =
+ case libmv::DISTORTION_MODEL_DIVISION: {
+ const DivisionCameraIntrinsics* division_intrinsics =
+ static_cast<const DivisionCameraIntrinsics*>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
LIBMV_DISTORTION_MODEL_DIVISION;
- camera_intrinsics_options->division_k1 = division_intrinsics->k1();
- camera_intrinsics_options->division_k2 = division_intrinsics->k2();
- break;
- }
-
- case libmv::DISTORTION_MODEL_NUKE:
- {
- const NukeCameraIntrinsics *nuke_intrinsics =
- static_cast<const NukeCameraIntrinsics *>(camera_intrinsics);
- camera_intrinsics_options->distortion_model =
- LIBMV_DISTORTION_MODEL_NUKE;
- camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1();
- camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2();
- break;
- }
+ camera_intrinsics_options->division_k1 = division_intrinsics->k1();
+ camera_intrinsics_options->division_k2 = division_intrinsics->k2();
+ break;
+ }
+
+ case libmv::DISTORTION_MODEL_NUKE: {
+ const NukeCameraIntrinsics* nuke_intrinsics =
+ static_cast<const NukeCameraIntrinsics*>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE;
+ camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1();
+ camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2();
+ break;
+ }
- case libmv::DISTORTION_MODEL_BROWN:
- {
- const BrownCameraIntrinsics *brown_intrinsics =
- static_cast<const BrownCameraIntrinsics *>(camera_intrinsics);
- camera_intrinsics_options->distortion_model =
+ case libmv::DISTORTION_MODEL_BROWN: {
+ const BrownCameraIntrinsics* brown_intrinsics =
+ static_cast<const BrownCameraIntrinsics*>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
LIBMV_DISTORTION_MODEL_BROWN;
- camera_intrinsics_options->brown_k1 = brown_intrinsics->k1();
- camera_intrinsics_options->brown_k2 = brown_intrinsics->k2();
- camera_intrinsics_options->brown_k3 = brown_intrinsics->k3();
- camera_intrinsics_options->brown_k4 = brown_intrinsics->k4();
- camera_intrinsics_options->brown_p1 = brown_intrinsics->p1();
- camera_intrinsics_options->brown_p2 = brown_intrinsics->p2();
- break;
- }
+ camera_intrinsics_options->brown_k1 = brown_intrinsics->k1();
+ camera_intrinsics_options->brown_k2 = brown_intrinsics->k2();
+ camera_intrinsics_options->brown_k3 = brown_intrinsics->k3();
+ camera_intrinsics_options->brown_k4 = brown_intrinsics->k4();
+ camera_intrinsics_options->brown_p1 = brown_intrinsics->p1();
+ camera_intrinsics_options->brown_p2 = brown_intrinsics->p2();
+ break;
+ }
- default:
- assert(!"Unknown distortion model");
+ default: assert(!"Unknown distortion model");
}
}
void libmv_cameraIntrinsicsUndistortByte(
const libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
+ const unsigned char* source_image,
int width,
int height,
float overscan,
int channels,
unsigned char* destination_image) {
- CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- camera_intrinsics->UndistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
+ CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics;
+ camera_intrinsics->UndistortBuffer(
+ source_image, width, height, overscan, channels, destination_image);
}
void libmv_cameraIntrinsicsUndistortFloat(
@@ -310,28 +286,22 @@ void libmv_cameraIntrinsicsUndistortFloat(
float overscan,
int channels,
float* destination_image) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- intrinsics->UndistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
+ CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics;
+ intrinsics->UndistortBuffer(
+ source_image, width, height, overscan, channels, destination_image);
}
void libmv_cameraIntrinsicsDistortByte(
const struct libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
+ const unsigned char* source_image,
int width,
int height,
float overscan,
int channels,
- unsigned char *destination_image) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- intrinsics->DistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
+ unsigned char* destination_image) {
+ CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics;
+ intrinsics->DistortBuffer(
+ source_image, width, height, overscan, channels, destination_image);
}
void libmv_cameraIntrinsicsDistortFloat(
@@ -342,12 +312,9 @@ void libmv_cameraIntrinsicsDistortFloat(
float overscan,
int channels,
float* destination_image) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- intrinsics->DistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
+ CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics;
+ intrinsics->DistortBuffer(
+ source_image, width, height, overscan, channels, destination_image);
}
void libmv_cameraIntrinsicsApply(
@@ -356,7 +323,7 @@ void libmv_cameraIntrinsicsApply(
double y,
double* x1,
double* y1) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics;
intrinsics->ApplyIntrinsics(x, y, x1, y1);
}
@@ -366,7 +333,7 @@ void libmv_cameraIntrinsicsInvert(
double y,
double* x1,
double* y1) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics;
intrinsics->InvertIntrinsics(x, y, x1, y1);
}
@@ -381,69 +348,63 @@ static void libmv_cameraIntrinsicsFillFromOptions(
camera_intrinsics_options->principal_point_y);
camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width,
- camera_intrinsics_options->image_height);
+ camera_intrinsics_options->image_height);
switch (camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- {
- PolynomialCameraIntrinsics *polynomial_intrinsics =
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL: {
+ PolynomialCameraIntrinsics* polynomial_intrinsics =
static_cast<PolynomialCameraIntrinsics*>(camera_intrinsics);
- polynomial_intrinsics->SetRadialDistortion(
- camera_intrinsics_options->polynomial_k1,
- camera_intrinsics_options->polynomial_k2,
- camera_intrinsics_options->polynomial_k3);
+ polynomial_intrinsics->SetRadialDistortion(
+ camera_intrinsics_options->polynomial_k1,
+ camera_intrinsics_options->polynomial_k2,
+ camera_intrinsics_options->polynomial_k3);
- break;
- }
+ break;
+ }
- case LIBMV_DISTORTION_MODEL_DIVISION:
- {
- DivisionCameraIntrinsics *division_intrinsics =
+ case LIBMV_DISTORTION_MODEL_DIVISION: {
+ DivisionCameraIntrinsics* division_intrinsics =
static_cast<DivisionCameraIntrinsics*>(camera_intrinsics);
- division_intrinsics->SetDistortion(
- camera_intrinsics_options->division_k1,
- camera_intrinsics_options->division_k2);
- break;
- }
+ division_intrinsics->SetDistortion(
+ camera_intrinsics_options->division_k1,
+ camera_intrinsics_options->division_k2);
+ break;
+ }
- case LIBMV_DISTORTION_MODEL_NUKE:
- {
- NukeCameraIntrinsics *nuke_intrinsics =
+ case LIBMV_DISTORTION_MODEL_NUKE: {
+ NukeCameraIntrinsics* nuke_intrinsics =
static_cast<NukeCameraIntrinsics*>(camera_intrinsics);
- nuke_intrinsics->SetDistortion(
- camera_intrinsics_options->nuke_k1,
- camera_intrinsics_options->nuke_k2);
- break;
- }
+ nuke_intrinsics->SetDistortion(camera_intrinsics_options->nuke_k1,
+ camera_intrinsics_options->nuke_k2);
+ break;
+ }
- case LIBMV_DISTORTION_MODEL_BROWN:
- {
- BrownCameraIntrinsics *brown_intrinsics =
+ case LIBMV_DISTORTION_MODEL_BROWN: {
+ BrownCameraIntrinsics* brown_intrinsics =
static_cast<BrownCameraIntrinsics*>(camera_intrinsics);
- brown_intrinsics->SetRadialDistortion(
- camera_intrinsics_options->brown_k1,
- camera_intrinsics_options->brown_k2,
- camera_intrinsics_options->brown_k3,
- camera_intrinsics_options->brown_k4);
- brown_intrinsics->SetTangentialDistortion(
+ brown_intrinsics->SetRadialDistortion(
+ camera_intrinsics_options->brown_k1,
+ camera_intrinsics_options->brown_k2,
+ camera_intrinsics_options->brown_k3,
+ camera_intrinsics_options->brown_k4);
+ brown_intrinsics->SetTangentialDistortion(
camera_intrinsics_options->brown_p1,
camera_intrinsics_options->brown_p2);
- break;
- }
+ break;
+ }
- default:
- assert(!"Unknown distortion model");
+ default: assert(!"Unknown distortion model");
}
}
CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
- CameraIntrinsics *camera_intrinsics = NULL;
+ CameraIntrinsics* camera_intrinsics = NULL;
switch (camera_intrinsics_options->distortion_model) {
case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics);
@@ -457,8 +418,7 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
case LIBMV_DISTORTION_MODEL_BROWN:
camera_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics);
break;
- default:
- assert(!"Unknown distortion model");
+ default: assert(!"Unknown distortion model");
}
libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options,
camera_intrinsics);
diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h
index eb6176770ec..8a65c93e6a4 100644
--- a/intern/libmv/intern/camera_intrinsics.h
+++ b/intern/libmv/intern/camera_intrinsics.h
@@ -56,10 +56,10 @@ typedef struct libmv_CameraIntrinsicsOptions {
double brown_p1, brown_p2;
} libmv_CameraIntrinsicsOptions;
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
+libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew(
const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options);
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
+libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy(
const libmv_CameraIntrinsics* libmv_intrinsics);
void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics);
@@ -76,7 +76,7 @@ void libmv_cameraIntrinsicsExtractOptions(
void libmv_cameraIntrinsicsUndistortByte(
const libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
+ const unsigned char* source_image,
int width,
int height,
float overscan,
@@ -94,12 +94,12 @@ void libmv_cameraIntrinsicsUndistortFloat(
void libmv_cameraIntrinsicsDistortByte(
const struct libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
+ const unsigned char* source_image,
int width,
int height,
float overscan,
int channels,
- unsigned char *destination_image);
+ unsigned char* destination_image);
void libmv_cameraIntrinsicsDistortFloat(
const libmv_CameraIntrinsics* libmv_intrinsics,
@@ -131,7 +131,7 @@ void libmv_cameraIntrinsicsInvert(
#ifdef __cplusplus
namespace libmv {
- class CameraIntrinsics;
+class CameraIntrinsics;
}
libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
diff --git a/intern/libmv/intern/detector.cc b/intern/libmv/intern/detector.cc
index 455e431f6f4..21f5b46595c 100644
--- a/intern/libmv/intern/detector.cc
+++ b/intern/libmv/intern/detector.cc
@@ -34,7 +34,7 @@ struct libmv_Features {
namespace {
-libmv_Features *libmv_featuresFromVector(
+libmv_Features* libmv_featuresFromVector(
const libmv::vector<Feature>& features) {
libmv_Features* libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1);
int count = features.size();
@@ -50,12 +50,12 @@ libmv_Features *libmv_featuresFromVector(
return libmv_features;
}
-void libmv_convertDetectorOptions(libmv_DetectOptions *options,
- DetectOptions *detector_options) {
+void libmv_convertDetectorOptions(libmv_DetectOptions* options,
+ DetectOptions* detector_options) {
switch (options->detector) {
-#define LIBMV_CONVERT(the_detector) \
- case LIBMV_DETECTOR_ ## the_detector: \
- detector_options->type = DetectOptions::the_detector; \
+#define LIBMV_CONVERT(the_detector) \
+ case LIBMV_DETECTOR_##the_detector: \
+ detector_options->type = DetectOptions::the_detector; \
break;
LIBMV_CONVERT(FAST)
LIBMV_CONVERT(MORAVEC)
@@ -72,7 +72,7 @@ void libmv_convertDetectorOptions(libmv_DetectOptions *options,
} // namespace
-libmv_Features *libmv_detectFeaturesByte(const unsigned char* image_buffer,
+libmv_Features* libmv_detectFeaturesByte(const unsigned char* image_buffer,
int width,
int height,
int channels,
@@ -133,7 +133,7 @@ void libmv_getFeature(const libmv_Features* libmv_features,
double* y,
double* score,
double* size) {
- Feature &feature = libmv_features->features[number];
+ Feature& feature = libmv_features->features[number];
*x = feature.x;
*y = feature.y;
*score = feature.score;
diff --git a/intern/libmv/intern/detector.h b/intern/libmv/intern/detector.h
index b36935fc67f..f21e78d7f2b 100644
--- a/intern/libmv/intern/detector.h
+++ b/intern/libmv/intern/detector.h
@@ -38,7 +38,7 @@ typedef struct libmv_DetectOptions {
int min_distance;
int fast_min_trackness;
int moravec_max_count;
- unsigned char *moravec_pattern;
+ unsigned char* moravec_pattern;
double harris_threshold;
} libmv_DetectOptions;
diff --git a/intern/libmv/intern/frame_accessor.cc b/intern/libmv/intern/frame_accessor.cc
index 9fde73f0d71..3a6c753cc8d 100644
--- a/intern/libmv/intern/frame_accessor.cc
+++ b/intern/libmv/intern/frame_accessor.cc
@@ -36,20 +36,18 @@ struct LibmvFrameAccessor : public FrameAccessor {
libmv_ReleaseImageCallback release_image_callback,
libmv_GetMaskForTrackCallback get_mask_for_track_callback,
libmv_ReleaseMaskCallback release_mask_callback)
- : user_data_(user_data),
- get_image_callback_(get_image_callback),
- release_image_callback_(release_image_callback),
- get_mask_for_track_callback_(get_mask_for_track_callback),
- release_mask_callback_(release_mask_callback) { }
+ : user_data_(user_data),
+ get_image_callback_(get_image_callback),
+ release_image_callback_(release_image_callback),
+ get_mask_for_track_callback_(get_mask_for_track_callback),
+ release_mask_callback_(release_mask_callback) {}
- virtual ~LibmvFrameAccessor() {
- }
+ virtual ~LibmvFrameAccessor() {}
libmv_InputMode get_libmv_input_mode(InputMode input_mode) {
switch (input_mode) {
-#define CHECK_INPUT_MODE(mode) \
- case mode: \
- return LIBMV_IMAGE_MODE_ ## mode;
+#define CHECK_INPUT_MODE(mode) \
+ case mode: return LIBMV_IMAGE_MODE_##mode;
CHECK_INPUT_MODE(MONO)
CHECK_INPUT_MODE(RGBA)
#undef CHECK_INPUT_MODE
@@ -59,8 +57,7 @@ struct LibmvFrameAccessor : public FrameAccessor {
return LIBMV_IMAGE_MODE_MONO;
}
- void get_libmv_region(const Region& region,
- libmv_Region* libmv_region) {
+ void get_libmv_region(const Region& region, libmv_Region* libmv_region) {
libmv_region->min[0] = region.min(0);
libmv_region->min[1] = region.min(1);
libmv_region->max[0] = region.max(0);
@@ -74,7 +71,7 @@ struct LibmvFrameAccessor : public FrameAccessor {
const Region* region,
const Transform* transform,
FloatImage* destination) {
- float *float_buffer;
+ float* float_buffer;
int width, height, channels;
libmv_Region libmv_region;
if (region) {
@@ -86,46 +83,41 @@ struct LibmvFrameAccessor : public FrameAccessor {
get_libmv_input_mode(input_mode),
downscale,
region != NULL ? &libmv_region : NULL,
- (libmv_FrameTransform*) transform,
+ (libmv_FrameTransform*)transform,
&float_buffer,
&width,
&height,
&channels);
// TODO(sergey): Dumb code for until we can set data directly.
- FloatImage temp_image(float_buffer,
- height,
- width,
- channels);
+ FloatImage temp_image(float_buffer, height, width, channels);
destination->CopyFrom(temp_image);
return cache_key;
}
- void ReleaseImage(Key cache_key) {
- release_image_callback_(cache_key);
- }
+ void ReleaseImage(Key cache_key) { release_image_callback_(cache_key); }
Key GetMaskForTrack(int clip,
int frame,
int track,
const Region* region,
FloatImage* destination) {
- float *float_buffer;
+ float* float_buffer;
int width, height;
libmv_Region libmv_region;
if (region) {
get_libmv_region(*region, &libmv_region);
}
- Key cache_key = get_mask_for_track_callback_(
- user_data_,
- clip,
- frame,
- track,
- region != NULL ? &libmv_region : NULL,
- &float_buffer,
- &width,
- &height);
+ Key cache_key =
+ get_mask_for_track_callback_(user_data_,
+ clip,
+ frame,
+ track,
+ region != NULL ? &libmv_region : NULL,
+ &float_buffer,
+ &width,
+ &height);
if (cache_key == NULL) {
// No mask for the given track.
@@ -133,30 +125,21 @@ struct LibmvFrameAccessor : public FrameAccessor {
}
// TODO(sergey): Dumb code for until we can set data directly.
- FloatImage temp_image(float_buffer,
- height,
- width,
- 1);
+ FloatImage temp_image(float_buffer, height, width, 1);
destination->CopyFrom(temp_image);
return cache_key;
}
- void ReleaseMask(Key key) {
- release_mask_callback_(key);
- }
+ void ReleaseMask(Key key) { release_mask_callback_(key); }
- bool GetClipDimensions(int /*clip*/, int * /*width*/, int * /*height*/) {
+ bool GetClipDimensions(int /*clip*/, int* /*width*/, int* /*height*/) {
return false;
}
- int NumClips() {
- return 1;
- }
+ int NumClips() { return 1; }
- int NumFrames(int /*clip*/) {
- return 0;
- }
+ int NumFrames(int /*clip*/) { return 0; }
libmv_FrameAccessorUserData* user_data_;
libmv_GetImageCallback get_image_callback_;
@@ -173,35 +156,35 @@ libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_ReleaseImageCallback release_image_callback,
libmv_GetMaskForTrackCallback get_mask_for_track_callback,
libmv_ReleaseMaskCallback release_mask_callback) {
- return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor,
- user_data,
- get_image_callback,
- release_image_callback,
- get_mask_for_track_callback,
- release_mask_callback);
+ return (libmv_FrameAccessor*)LIBMV_OBJECT_NEW(LibmvFrameAccessor,
+ user_data,
+ get_image_callback,
+ release_image_callback,
+ get_mask_for_track_callback,
+ release_mask_callback);
}
void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) {
LIBMV_OBJECT_DELETE(frame_accessor, LibmvFrameAccessor);
}
-int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform) {
- return ((FrameAccessor::Transform*) transform)->key();
+int64_t libmv_frameAccessorgetTransformKey(
+ const libmv_FrameTransform* transform) {
+ return ((FrameAccessor::Transform*)transform)->key();
}
-void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform,
- const libmv_FloatImage *input_image,
- libmv_FloatImage *output_image) {
+void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* transform,
+ const libmv_FloatImage* input_image,
+ libmv_FloatImage* output_image) {
const FloatImage input(input_image->buffer,
input_image->height,
input_image->width,
input_image->channels);
FloatImage output;
- ((FrameAccessor::Transform*) transform)->run(input,
- &output);
+ ((FrameAccessor::Transform*)transform)->run(input, &output);
- int num_pixels = output.Width() *output.Height() * output.Depth();
+ int num_pixels = output.Width() * output.Height() * output.Depth();
output_image->buffer = new float[num_pixels];
memcpy(output_image->buffer, output.Data(), num_pixels * sizeof(float));
output_image->width = output.Width();
diff --git a/intern/libmv/intern/frame_accessor.h b/intern/libmv/intern/frame_accessor.h
index 6bccb305282..39a3bc5eb1d 100644
--- a/intern/libmv/intern/frame_accessor.h
+++ b/intern/libmv/intern/frame_accessor.h
@@ -32,14 +32,14 @@ extern "C" {
typedef struct libmv_FrameAccessor libmv_FrameAccessor;
typedef struct libmv_FrameTransform libmv_FrameTransform;
typedef struct libmv_FrameAccessorUserData libmv_FrameAccessorUserData;
-typedef void *libmv_CacheKey;
+typedef void* libmv_CacheKey;
typedef enum {
LIBMV_IMAGE_MODE_MONO,
LIBMV_IMAGE_MODE_RGBA,
} libmv_InputMode;
-typedef libmv_CacheKey (*libmv_GetImageCallback) (
+typedef libmv_CacheKey (*libmv_GetImageCallback)(
libmv_FrameAccessorUserData* user_data,
int clip,
int frame,
@@ -52,9 +52,9 @@ typedef libmv_CacheKey (*libmv_GetImageCallback) (
int* height,
int* channels);
-typedef void (*libmv_ReleaseImageCallback) (libmv_CacheKey cache_key);
+typedef void (*libmv_ReleaseImageCallback)(libmv_CacheKey cache_key);
-typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) (
+typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback)(
libmv_FrameAccessorUserData* user_data,
int clip,
int frame,
@@ -63,7 +63,7 @@ typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) (
float** destination,
int* width,
int* height);
-typedef void (*libmv_ReleaseMaskCallback) (libmv_CacheKey cache_key);
+typedef void (*libmv_ReleaseMaskCallback)(libmv_CacheKey cache_key);
libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_FrameAccessorUserData* user_data,
@@ -73,11 +73,12 @@ libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_ReleaseMaskCallback release_mask_callback);
void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor);
-int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform);
+int64_t libmv_frameAccessorgetTransformKey(
+ const libmv_FrameTransform* transform);
-void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform,
- const libmv_FloatImage *input_image,
- libmv_FloatImage *output_image);
+void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* transform,
+ const libmv_FloatImage* input_image,
+ libmv_FloatImage* output_image);
#ifdef __cplusplus
}
#endif
diff --git a/intern/libmv/intern/homography.cc b/intern/libmv/intern/homography.cc
index 179aeaa08aa..dc1009b5636 100644
--- a/intern/libmv/intern/homography.cc
+++ b/intern/libmv/intern/homography.cc
@@ -41,10 +41,8 @@ void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2],
LG << "x2: " << x2_mat;
libmv::EstimateHomographyOptions options;
- libmv::EstimateHomography2DFromCorrespondences(x1_mat,
- x2_mat,
- options,
- &H_mat);
+ libmv::EstimateHomography2DFromCorrespondences(
+ x1_mat, x2_mat, options, &H_mat);
LG << "H: " << H_mat;
diff --git a/intern/libmv/intern/image.cc b/intern/libmv/intern/image.cc
index a6e09277680..564e4762448 100644
--- a/intern/libmv/intern/image.cc
+++ b/intern/libmv/intern/image.cc
@@ -21,14 +21,14 @@
#include "intern/utildefines.h"
#include "libmv/tracking/track_region.h"
-#include <cassert>
#include <png.h>
+#include <cassert>
using libmv::FloatImage;
using libmv::SamplePlanarPatch;
-void libmv_floatImageDestroy(libmv_FloatImage *image) {
- delete [] image->buffer;
+void libmv_floatImageDestroy(libmv_FloatImage* image) {
+ delete[] image->buffer;
}
/* Image <-> buffers conversion */
@@ -63,8 +63,7 @@ void libmv_floatBufferToFloatImage(const float* buffer,
}
}
-void libmv_floatImageToFloatBuffer(const FloatImage &image,
- float* buffer) {
+void libmv_floatImageToFloatBuffer(const FloatImage& image, float* buffer) {
for (int y = 0, a = 0; y < image.Height(); y++) {
for (int x = 0; x < image.Width(); x++) {
for (int k = 0; k < image.Depth(); k++) {
@@ -74,9 +73,9 @@ void libmv_floatImageToFloatBuffer(const FloatImage &image,
}
}
-void libmv_floatImageToByteBuffer(const libmv::FloatImage &image,
+void libmv_floatImageToByteBuffer(const libmv::FloatImage& image,
unsigned char* buffer) {
- for (int y = 0, a= 0; y < image.Height(); y++) {
+ for (int y = 0, a = 0; y < image.Height(); y++) {
for (int x = 0; x < image.Width(); x++) {
for (int k = 0; k < image.Depth(); k++) {
buffer[a++] = image(y, x, k) * 255.0f;
@@ -93,7 +92,7 @@ static bool savePNGImage(png_bytep* row_pointers,
const char* file_name) {
png_infop info_ptr;
png_structp png_ptr;
- FILE *fp = fopen(file_name, "wb");
+ FILE* fp = fopen(file_name, "wb");
if (fp == NULL) {
return false;
@@ -153,7 +152,7 @@ bool libmv_saveImage(const FloatImage& image,
int x0,
int y0) {
int x, y;
- png_bytep *row_pointers;
+ png_bytep* row_pointers;
assert(image.Depth() == 1);
@@ -180,9 +179,8 @@ bool libmv_saveImage(const FloatImage& image,
static int image_counter = 0;
char file_name[128];
- snprintf(file_name, sizeof(file_name),
- "%s_%02d.png",
- prefix, ++image_counter);
+ snprintf(
+ file_name, sizeof(file_name), "%s_%02d.png", prefix, ++image_counter);
bool result = savePNGImage(row_pointers,
image.Width(),
image.Height(),
@@ -191,9 +189,9 @@ bool libmv_saveImage(const FloatImage& image,
file_name);
for (y = 0; y < image.Height(); y++) {
- delete [] row_pointers[y];
+ delete[] row_pointers[y];
}
- delete [] row_pointers;
+ delete[] row_pointers;
return result;
}
@@ -211,7 +209,7 @@ void libmv_samplePlanarPatchFloat(const float* image,
double* warped_position_x,
double* warped_position_y) {
FloatImage libmv_image, libmv_patch, libmv_mask;
- FloatImage *libmv_mask_for_sample = NULL;
+ FloatImage* libmv_mask_for_sample = NULL;
libmv_floatBufferToFloatImage(image, width, height, channels, &libmv_image);
@@ -221,8 +219,10 @@ void libmv_samplePlanarPatchFloat(const float* image,
}
SamplePlanarPatch(libmv_image,
- xs, ys,
- num_samples_x, num_samples_y,
+ xs,
+ ys,
+ num_samples_x,
+ num_samples_y,
libmv_mask_for_sample,
&libmv_patch,
warped_position_x,
@@ -232,19 +232,19 @@ void libmv_samplePlanarPatchFloat(const float* image,
}
void libmv_samplePlanarPatchByte(const unsigned char* image,
- int width,
- int height,
- int channels,
- const double* xs,
- const double* ys,
- int num_samples_x,
- int num_samples_y,
- const float* mask,
- unsigned char* patch,
- double* warped_position_x,
- double* warped_position_y) {
+ int width,
+ int height,
+ int channels,
+ const double* xs,
+ const double* ys,
+ int num_samples_x,
+ int num_samples_y,
+ const float* mask,
+ unsigned char* patch,
+ double* warped_position_x,
+ double* warped_position_y) {
libmv::FloatImage libmv_image, libmv_patch, libmv_mask;
- libmv::FloatImage *libmv_mask_for_sample = NULL;
+ libmv::FloatImage* libmv_mask_for_sample = NULL;
libmv_byteBufferToFloatImage(image, width, height, channels, &libmv_image);
@@ -254,8 +254,10 @@ void libmv_samplePlanarPatchByte(const unsigned char* image,
}
libmv::SamplePlanarPatch(libmv_image,
- xs, ys,
- num_samples_x, num_samples_y,
+ xs,
+ ys,
+ num_samples_x,
+ num_samples_y,
libmv_mask_for_sample,
&libmv_patch,
warped_position_x,
diff --git a/intern/libmv/intern/image.h b/intern/libmv/intern/image.h
index a1381a4c216..02cef86a127 100644
--- a/intern/libmv/intern/image.h
+++ b/intern/libmv/intern/image.h
@@ -35,7 +35,7 @@ void libmv_floatBufferToFloatImage(const float* buffer,
libmv::FloatImage* image);
void libmv_floatImageToFloatBuffer(const libmv::FloatImage& image,
- float *buffer);
+ float* buffer);
void libmv_floatImageToByteBuffer(const libmv::FloatImage& image,
unsigned char* buffer);
@@ -51,13 +51,13 @@ extern "C" {
#endif
typedef struct libmv_FloatImage {
- float *buffer;
+ float* buffer;
int width;
int height;
int channels;
} libmv_FloatImage;
-void libmv_floatImageDestroy(libmv_FloatImage *image);
+void libmv_floatImageDestroy(libmv_FloatImage* image);
void libmv_samplePlanarPatchFloat(const float* image,
int width,
@@ -72,18 +72,18 @@ void libmv_samplePlanarPatchFloat(const float* image,
double* warped_position_x,
double* warped_position_y);
- void libmv_samplePlanarPatchByte(const unsigned char* image,
- int width,
- int height,
- int channels,
- const double* xs,
- const double* ys,
- int num_samples_x,
- int num_samples_y,
- const float* mask,
- unsigned char* patch,
- double* warped_position_x,
- double* warped_position_y);
+void libmv_samplePlanarPatchByte(const unsigned char* image,
+ int width,
+ int height,
+ int channels,
+ const double* xs,
+ const double* ys,
+ int num_samples_x,
+ int num_samples_y,
+ const float* mask,
+ unsigned char* patch,
+ double* warped_position_x,
+ double* warped_position_y);
#ifdef __cplusplus
}
diff --git a/intern/libmv/intern/reconstruction.cc b/intern/libmv/intern/reconstruction.cc
index 0f4e890d4ca..430607461da 100644
--- a/intern/libmv/intern/reconstruction.cc
+++ b/intern/libmv/intern/reconstruction.cc
@@ -24,8 +24,8 @@
#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/bundle.h"
-#include "libmv/simple_pipeline/keyframe_selection.h"
#include "libmv/simple_pipeline/initialize_reconstruction.h"
+#include "libmv/simple_pipeline/keyframe_selection.h"
#include "libmv/simple_pipeline/modal_solver.h"
#include "libmv/simple_pipeline/pipeline.h"
#include "libmv/simple_pipeline/reconstruction_scale.h"
@@ -39,19 +39,19 @@ using libmv::EuclideanScaleToUnity;
using libmv::Marker;
using libmv::ProgressUpdateCallback;
-using libmv::PolynomialCameraIntrinsics;
-using libmv::Tracks;
using libmv::EuclideanBundle;
using libmv::EuclideanCompleteReconstruction;
using libmv::EuclideanReconstructTwoFrames;
using libmv::EuclideanReprojectionError;
+using libmv::PolynomialCameraIntrinsics;
+using libmv::Tracks;
struct libmv_Reconstruction {
EuclideanReconstruction reconstruction;
/* Used for per-track average error calculation after reconstruction */
Tracks tracks;
- CameraIntrinsics *intrinsics;
+ CameraIntrinsics* intrinsics;
double error;
bool is_valid;
@@ -63,7 +63,7 @@ class ReconstructUpdateCallback : public ProgressUpdateCallback {
public:
ReconstructUpdateCallback(
reconstruct_progress_update_cb progress_update_callback,
- void *callback_customdata) {
+ void* callback_customdata) {
progress_update_callback_ = progress_update_callback;
callback_customdata_ = callback_customdata;
}
@@ -73,13 +73,14 @@ class ReconstructUpdateCallback : public ProgressUpdateCallback {
progress_update_callback_(callback_customdata_, progress, message);
}
}
+
protected:
reconstruct_progress_update_cb progress_update_callback_;
void* callback_customdata_;
};
void libmv_solveRefineIntrinsics(
- const Tracks &tracks,
+ const Tracks& tracks,
const int refine_intrinsics,
const int bundle_constraints,
reconstruct_progress_update_cb progress_update_callback,
@@ -96,11 +97,11 @@ void libmv_solveRefineIntrinsics(
bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT;
}
-#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \
- do { \
- if (refine_intrinsics & LIBMV_REFINE_ ## type ##_DISTORTION_ ## coefficient) { \
- bundle_intrinsics |= libmv::BUNDLE_ ## type ## _ ## coefficient; \
- } \
+#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \
+ do { \
+ if (refine_intrinsics & LIBMV_REFINE_##type##_DISTORTION_##coefficient) { \
+ bundle_intrinsics |= libmv::BUNDLE_##type##_##coefficient; \
+ } \
} while (0)
SET_DISTORTION_FLAG_CHECKED(RADIAL, K1);
@@ -123,20 +124,19 @@ void libmv_solveRefineIntrinsics(
}
void finishReconstruction(
- const Tracks &tracks,
- const CameraIntrinsics &camera_intrinsics,
- libmv_Reconstruction *libmv_reconstruction,
+ const Tracks& tracks,
+ const CameraIntrinsics& camera_intrinsics,
+ libmv_Reconstruction* libmv_reconstruction,
reconstruct_progress_update_cb progress_update_callback,
- void *callback_customdata) {
- EuclideanReconstruction &reconstruction =
- libmv_reconstruction->reconstruction;
+ void* callback_customdata) {
+ EuclideanReconstruction& reconstruction =
+ libmv_reconstruction->reconstruction;
/* Reprojection error calculation. */
progress_update_callback(callback_customdata, 1.0, "Finishing solution");
libmv_reconstruction->tracks = tracks;
- libmv_reconstruction->error = EuclideanReprojectionError(tracks,
- reconstruction,
- camera_intrinsics);
+ libmv_reconstruction->error =
+ EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
}
bool selectTwoKeyframesBasedOnGRICAndVariance(
@@ -148,9 +148,8 @@ bool selectTwoKeyframesBasedOnGRICAndVariance(
libmv::vector<int> keyframes;
/* Get list of all keyframe candidates first. */
- SelectKeyframesBasedOnGRICAndVariance(normalized_tracks,
- camera_intrinsics,
- keyframes);
+ SelectKeyframesBasedOnGRICAndVariance(
+ normalized_tracks, camera_intrinsics, keyframes);
if (keyframes.size() < 2) {
LG << "Not enough keyframes detected by GRIC";
@@ -175,24 +174,20 @@ bool selectTwoKeyframesBasedOnGRICAndVariance(
EuclideanReconstruction reconstruction;
int current_keyframe = keyframes[i];
libmv::vector<Marker> keyframe_markers =
- normalized_tracks.MarkersForTracksInBothImages(previous_keyframe,
- current_keyframe);
+ normalized_tracks.MarkersForTracksInBothImages(previous_keyframe,
+ current_keyframe);
Tracks keyframe_tracks(keyframe_markers);
/* get a solution from two keyframes only */
EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction);
EuclideanBundle(keyframe_tracks, &reconstruction);
- EuclideanCompleteReconstruction(keyframe_tracks,
- &reconstruction,
- NULL);
+ EuclideanCompleteReconstruction(keyframe_tracks, &reconstruction, NULL);
- double current_error = EuclideanReprojectionError(tracks,
- reconstruction,
- camera_intrinsics);
+ double current_error =
+ EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
- LG << "Error between " << previous_keyframe
- << " and " << current_keyframe
+ LG << "Error between " << previous_keyframe << " and " << current_keyframe
<< ": " << current_error;
if (current_error < best_error) {
@@ -214,53 +209,49 @@ Marker libmv_projectMarker(const EuclideanPoint& point,
projected /= projected(2);
libmv::Marker reprojected_marker;
- intrinsics.ApplyIntrinsics(projected(0), projected(1),
- &reprojected_marker.x,
- &reprojected_marker.y);
+ intrinsics.ApplyIntrinsics(
+ projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
reprojected_marker.image = camera.image;
reprojected_marker.track = point.track;
return reprojected_marker;
}
-void libmv_getNormalizedTracks(const Tracks &tracks,
- const CameraIntrinsics &camera_intrinsics,
- Tracks *normalized_tracks) {
+void libmv_getNormalizedTracks(const Tracks& tracks,
+ const CameraIntrinsics& camera_intrinsics,
+ Tracks* normalized_tracks) {
libmv::vector<Marker> markers = tracks.AllMarkers();
for (int i = 0; i < markers.size(); ++i) {
- Marker &marker = markers[i];
- camera_intrinsics.InvertIntrinsics(marker.x, marker.y,
- &marker.x, &marker.y);
- normalized_tracks->Insert(marker.image,
- marker.track,
- marker.x, marker.y,
- marker.weight);
+ Marker& marker = markers[i];
+ camera_intrinsics.InvertIntrinsics(
+ marker.x, marker.y, &marker.x, &marker.y);
+ normalized_tracks->Insert(
+ marker.image, marker.track, marker.x, marker.y, marker.weight);
}
}
} // namespace
-libmv_Reconstruction *libmv_solveReconstruction(
+libmv_Reconstruction* libmv_solveReconstruction(
const libmv_Tracks* libmv_tracks,
const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
libmv_ReconstructionOptions* libmv_reconstruction_options,
reconstruct_progress_update_cb progress_update_callback,
void* callback_customdata) {
- libmv_Reconstruction *libmv_reconstruction =
- LIBMV_OBJECT_NEW(libmv_Reconstruction);
+ libmv_Reconstruction* libmv_reconstruction =
+ LIBMV_OBJECT_NEW(libmv_Reconstruction);
- Tracks &tracks = *((Tracks *) libmv_tracks);
- EuclideanReconstruction &reconstruction =
- libmv_reconstruction->reconstruction;
+ Tracks& tracks = *((Tracks*)libmv_tracks);
+ EuclideanReconstruction& reconstruction =
+ libmv_reconstruction->reconstruction;
ReconstructUpdateCallback update_callback =
- ReconstructUpdateCallback(progress_update_callback,
- callback_customdata);
+ ReconstructUpdateCallback(progress_update_callback, callback_customdata);
/* Retrieve reconstruction options from C-API to libmv API. */
- CameraIntrinsics *camera_intrinsics;
+ CameraIntrinsics* camera_intrinsics;
camera_intrinsics = libmv_reconstruction->intrinsics =
- libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
+ libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
/* Invert the camera intrinsics/ */
Tracks normalized_tracks;
@@ -276,10 +267,10 @@ libmv_Reconstruction *libmv_solveReconstruction(
update_callback.invoke(0, "Selecting keyframes");
if (selectTwoKeyframesBasedOnGRICAndVariance(tracks,
- normalized_tracks,
- *camera_intrinsics,
- keyframe1,
- keyframe2)) {
+ normalized_tracks,
+ *camera_intrinsics,
+ keyframe1,
+ keyframe2)) {
/* so keyframes in the interface would be updated */
libmv_reconstruction_options->keyframe1 = keyframe1;
libmv_reconstruction_options->keyframe2 = keyframe2;
@@ -290,7 +281,7 @@ libmv_Reconstruction *libmv_solveReconstruction(
LG << "frames to init from: " << keyframe1 << " " << keyframe2;
libmv::vector<Marker> keyframe_markers =
- normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+ normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
LG << "number of markers for init: " << keyframe_markers.size();
@@ -309,14 +300,12 @@ libmv_Reconstruction *libmv_solveReconstruction(
}
EuclideanBundle(normalized_tracks, &reconstruction);
- EuclideanCompleteReconstruction(normalized_tracks,
- &reconstruction,
- &update_callback);
+ EuclideanCompleteReconstruction(
+ normalized_tracks, &reconstruction, &update_callback);
/* Refinement. */
if (libmv_reconstruction_options->refine_intrinsics) {
- libmv_solveRefineIntrinsics(
- tracks,
+ libmv_solveRefineIntrinsics(tracks,
libmv_reconstruction_options->refine_intrinsics,
libmv::BUNDLE_NO_CONSTRAINTS,
progress_update_callback,
@@ -336,31 +325,29 @@ libmv_Reconstruction *libmv_solveReconstruction(
callback_customdata);
libmv_reconstruction->is_valid = true;
- return (libmv_Reconstruction *) libmv_reconstruction;
+ return (libmv_Reconstruction*)libmv_reconstruction;
}
-libmv_Reconstruction *libmv_solveModal(
- const libmv_Tracks *libmv_tracks,
- const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
- const libmv_ReconstructionOptions *libmv_reconstruction_options,
+libmv_Reconstruction* libmv_solveModal(
+ const libmv_Tracks* libmv_tracks,
+ const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
+ const libmv_ReconstructionOptions* libmv_reconstruction_options,
reconstruct_progress_update_cb progress_update_callback,
- void *callback_customdata) {
- libmv_Reconstruction *libmv_reconstruction =
- LIBMV_OBJECT_NEW(libmv_Reconstruction);
+ void* callback_customdata) {
+ libmv_Reconstruction* libmv_reconstruction =
+ LIBMV_OBJECT_NEW(libmv_Reconstruction);
- Tracks &tracks = *((Tracks *) libmv_tracks);
- EuclideanReconstruction &reconstruction =
- libmv_reconstruction->reconstruction;
+ Tracks& tracks = *((Tracks*)libmv_tracks);
+ EuclideanReconstruction& reconstruction =
+ libmv_reconstruction->reconstruction;
ReconstructUpdateCallback update_callback =
- ReconstructUpdateCallback(progress_update_callback,
- callback_customdata);
+ ReconstructUpdateCallback(progress_update_callback, callback_customdata);
/* Retrieve reconstruction options from C-API to libmv API. */
- CameraIntrinsics *camera_intrinsics;
+ CameraIntrinsics* camera_intrinsics;
camera_intrinsics = libmv_reconstruction->intrinsics =
- libmv_cameraIntrinsicsCreateFromOptions(
- libmv_camera_intrinsics_options);
+ libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
/* Invert the camera intrinsics. */
Tracks normalized_tracks;
@@ -378,11 +365,11 @@ libmv_Reconstruction *libmv_solveModal(
/* Refinement. */
if (libmv_reconstruction_options->refine_intrinsics) {
- libmv_solveRefineIntrinsics(
- tracks,
+ libmv_solveRefineIntrinsics(tracks,
libmv_reconstruction_options->refine_intrinsics,
libmv::BUNDLE_NO_TRANSLATION,
- progress_update_callback, callback_customdata,
+ progress_update_callback,
+ callback_customdata,
&reconstruction,
camera_intrinsics);
}
@@ -395,26 +382,25 @@ libmv_Reconstruction *libmv_solveModal(
callback_customdata);
libmv_reconstruction->is_valid = true;
- return (libmv_Reconstruction *) libmv_reconstruction;
+ return (libmv_Reconstruction*)libmv_reconstruction;
}
-int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction) {
+int libmv_reconstructionIsValid(libmv_Reconstruction* libmv_reconstruction) {
return libmv_reconstruction->is_valid;
}
-void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction) {
+void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction) {
LIBMV_OBJECT_DELETE(libmv_reconstruction->intrinsics, CameraIntrinsics);
LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction);
}
int libmv_reprojectionPointForTrack(
- const libmv_Reconstruction *libmv_reconstruction,
+ const libmv_Reconstruction* libmv_reconstruction,
int track,
double pos[3]) {
- const EuclideanReconstruction *reconstruction =
- &libmv_reconstruction->reconstruction;
- const EuclideanPoint *point =
- reconstruction->PointForTrack(track);
+ const EuclideanReconstruction* reconstruction =
+ &libmv_reconstruction->reconstruction;
+ const EuclideanPoint* point = reconstruction->PointForTrack(track);
if (point) {
pos[0] = point->X[0];
pos[1] = point->X[2];
@@ -425,23 +411,22 @@ int libmv_reprojectionPointForTrack(
}
double libmv_reprojectionErrorForTrack(
- const libmv_Reconstruction *libmv_reconstruction,
- int track) {
- const EuclideanReconstruction *reconstruction =
- &libmv_reconstruction->reconstruction;
- const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics;
+ const libmv_Reconstruction* libmv_reconstruction, int track) {
+ const EuclideanReconstruction* reconstruction =
+ &libmv_reconstruction->reconstruction;
+ const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics;
libmv::vector<Marker> markers =
- libmv_reconstruction->tracks.MarkersForTrack(track);
+ libmv_reconstruction->tracks.MarkersForTrack(track);
int num_reprojected = 0;
double total_error = 0.0;
for (int i = 0; i < markers.size(); ++i) {
double weight = markers[i].weight;
- const EuclideanCamera *camera =
- reconstruction->CameraForImage(markers[i].image);
- const EuclideanPoint *point =
- reconstruction->PointForTrack(markers[i].track);
+ const EuclideanCamera* camera =
+ reconstruction->CameraForImage(markers[i].image);
+ const EuclideanPoint* point =
+ reconstruction->PointForTrack(markers[i].track);
if (!camera || !point || weight == 0.0) {
continue;
@@ -450,7 +435,7 @@ double libmv_reprojectionErrorForTrack(
num_reprojected++;
Marker reprojected_marker =
- libmv_projectMarker(*point, *camera, *intrinsics);
+ libmv_projectMarker(*point, *camera, *intrinsics);
double ex = (reprojected_marker.x - markers[i].x) * weight;
double ey = (reprojected_marker.y - markers[i].y) * weight;
@@ -461,14 +446,13 @@ double libmv_reprojectionErrorForTrack(
}
double libmv_reprojectionErrorForImage(
- const libmv_Reconstruction *libmv_reconstruction,
- int image) {
- const EuclideanReconstruction *reconstruction =
- &libmv_reconstruction->reconstruction;
- const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics;
+ const libmv_Reconstruction* libmv_reconstruction, int image) {
+ const EuclideanReconstruction* reconstruction =
+ &libmv_reconstruction->reconstruction;
+ const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics;
libmv::vector<Marker> markers =
- libmv_reconstruction->tracks.MarkersInImage(image);
- const EuclideanCamera *camera = reconstruction->CameraForImage(image);
+ libmv_reconstruction->tracks.MarkersInImage(image);
+ const EuclideanCamera* camera = reconstruction->CameraForImage(image);
int num_reprojected = 0;
double total_error = 0.0;
@@ -477,8 +461,8 @@ double libmv_reprojectionErrorForImage(
}
for (int i = 0; i < markers.size(); ++i) {
- const EuclideanPoint *point =
- reconstruction->PointForTrack(markers[i].track);
+ const EuclideanPoint* point =
+ reconstruction->PointForTrack(markers[i].track);
if (!point) {
continue;
@@ -487,7 +471,7 @@ double libmv_reprojectionErrorForImage(
num_reprojected++;
Marker reprojected_marker =
- libmv_projectMarker(*point, *camera, *intrinsics);
+ libmv_projectMarker(*point, *camera, *intrinsics);
double ex = (reprojected_marker.x - markers[i].x) * markers[i].weight;
double ey = (reprojected_marker.y - markers[i].y) * markers[i].weight;
@@ -498,13 +482,12 @@ double libmv_reprojectionErrorForImage(
}
int libmv_reprojectionCameraForImage(
- const libmv_Reconstruction *libmv_reconstruction,
+ const libmv_Reconstruction* libmv_reconstruction,
int image,
double mat[4][4]) {
- const EuclideanReconstruction *reconstruction =
- &libmv_reconstruction->reconstruction;
- const EuclideanCamera *camera =
- reconstruction->CameraForImage(image);
+ const EuclideanReconstruction* reconstruction =
+ &libmv_reconstruction->reconstruction;
+ const EuclideanCamera* camera = reconstruction->CameraForImage(image);
if (camera) {
for (int j = 0; j < 3; ++j) {
@@ -541,11 +524,11 @@ int libmv_reprojectionCameraForImage(
}
double libmv_reprojectionError(
- const libmv_Reconstruction *libmv_reconstruction) {
+ const libmv_Reconstruction* libmv_reconstruction) {
return libmv_reconstruction->error;
}
-libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
- libmv_Reconstruction *libmv_reconstruction) {
- return (libmv_CameraIntrinsics *) libmv_reconstruction->intrinsics;
+libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics(
+ libmv_Reconstruction* libmv_reconstruction) {
+ return (libmv_CameraIntrinsics*)libmv_reconstruction->intrinsics;
}
diff --git a/intern/libmv/intern/reconstruction.h b/intern/libmv/intern/reconstruction.h
index 408ac884684..600bc92ccfc 100644
--- a/intern/libmv/intern/reconstruction.h
+++ b/intern/libmv/intern/reconstruction.h
@@ -31,17 +31,16 @@ struct libmv_CameraIntrinsicsOptions;
typedef struct libmv_Reconstruction libmv_Reconstruction;
enum {
- LIBMV_REFINE_FOCAL_LENGTH = (1 << 0),
- LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1),
-
- LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2),
- LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 3),
- LIBMV_REFINE_RADIAL_DISTORTION_K3 = (1 << 4),
- LIBMV_REFINE_RADIAL_DISTORTION_K4 = (1 << 5),
- LIBMV_REFINE_RADIAL_DISTORTION = (LIBMV_REFINE_RADIAL_DISTORTION_K1 |
- LIBMV_REFINE_RADIAL_DISTORTION_K2 |
- LIBMV_REFINE_RADIAL_DISTORTION_K3 |
- LIBMV_REFINE_RADIAL_DISTORTION_K4),
+ LIBMV_REFINE_FOCAL_LENGTH = (1 << 0),
+ LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1),
+
+ LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2),
+ LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 3),
+ LIBMV_REFINE_RADIAL_DISTORTION_K3 = (1 << 4),
+ LIBMV_REFINE_RADIAL_DISTORTION_K4 = (1 << 5),
+ LIBMV_REFINE_RADIAL_DISTORTION =
+ (LIBMV_REFINE_RADIAL_DISTORTION_K1 | LIBMV_REFINE_RADIAL_DISTORTION_K2 |
+ LIBMV_REFINE_RADIAL_DISTORTION_K3 | LIBMV_REFINE_RADIAL_DISTORTION_K4),
LIBMV_REFINE_TANGENTIAL_DISTORTION_P1 = (1 << 6),
LIBMV_REFINE_TANGENTIAL_DISTORTION_P2 = (1 << 7),
@@ -55,9 +54,9 @@ typedef struct libmv_ReconstructionOptions {
int refine_intrinsics;
} libmv_ReconstructionOptions;
-typedef void (*reconstruct_progress_update_cb) (void* customdata,
- double progress,
- const char* message);
+typedef void (*reconstruct_progress_update_cb)(void* customdata,
+ double progress,
+ const char* message);
libmv_Reconstruction* libmv_solveReconstruction(
const struct libmv_Tracks* libmv_tracks,
@@ -73,35 +72,32 @@ libmv_Reconstruction* libmv_solveModal(
reconstruct_progress_update_cb progress_update_callback,
void* callback_customdata);
-int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction);
+int libmv_reconstructionIsValid(libmv_Reconstruction* libmv_reconstruction);
void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction);
int libmv_reprojectionPointForTrack(
- const libmv_Reconstruction* libmv_reconstruction,
- int track,
- double pos[3]);
+ const libmv_Reconstruction* libmv_reconstruction, int track, double pos[3]);
double libmv_reprojectionErrorForTrack(
- const libmv_Reconstruction* libmv_reconstruction,
- int track);
+ const libmv_Reconstruction* libmv_reconstruction, int track);
double libmv_reprojectionErrorForImage(
- const libmv_Reconstruction* libmv_reconstruction,
- int image);
+ const libmv_Reconstruction* libmv_reconstruction, int image);
int libmv_reprojectionCameraForImage(
const libmv_Reconstruction* libmv_reconstruction,
int image,
double mat[4][4]);
-double libmv_reprojectionError(const libmv_Reconstruction* libmv_reconstruction);
+double libmv_reprojectionError(
+ const libmv_Reconstruction* libmv_reconstruction);
struct libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics(
- libmv_Reconstruction *libmv_Reconstruction);
+ libmv_Reconstruction* libmv_Reconstruction);
#ifdef __cplusplus
}
#endif
-#endif // LIBMV_C_API_RECONSTRUCTION_H_
+#endif // LIBMV_C_API_RECONSTRUCTION_H_
diff --git a/intern/libmv/intern/stub.cc b/intern/libmv/intern/stub.cc
index 47e1896b4cf..1920042b4ec 100644
--- a/intern/libmv/intern/stub.cc
+++ b/intern/libmv/intern/stub.cc
@@ -24,7 +24,7 @@
/* ************ Logging ************ */
-void libmv_initLogging(const char * /*argv0*/) {
+void libmv_initLogging(const char* /*argv0*/) {
}
void libmv_startDebugLogging(void) {
@@ -36,18 +36,18 @@ void libmv_setLoggingVerbosity(int /*verbosity*/) {
/* ************ Planar tracker ************ */
/* TrackRegion (new planar tracker) */
-int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/,
- const float * /*image1*/,
+int libmv_trackRegion(const libmv_TrackRegionOptions* /*options*/,
+ const float* /*image1*/,
int /*image1_width*/,
int /*image1_height*/,
- const float * /*image2*/,
+ const float* /*image2*/,
int /*image2_width*/,
int /*image2_height*/,
- const double *x1,
- const double *y1,
- libmv_TrackRegionResult *result,
- double *x2,
- double *y2) {
+ const double* x1,
+ const double* y1,
+ libmv_TrackRegionResult* result,
+ double* x2,
+ double* y2) {
/* Convert to doubles for the libmv api. The four corners and the center. */
for (int i = 0; i < 5; ++i) {
x2[i] = x1[i];
@@ -61,46 +61,46 @@ int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/,
return false;
}
-void libmv_samplePlanarPatchFloat(const float * /*image*/,
+void libmv_samplePlanarPatchFloat(const float* /*image*/,
int /*width*/,
int /*height*/,
int /*channels*/,
- const double * /*xs*/,
- const double * /*ys*/,
+ const double* /*xs*/,
+ const double* /*ys*/,
int /*num_samples_x*/,
int /*num_samples_y*/,
- const float * /*mask*/,
- float * /*patch*/,
- double * /*warped_position_x*/,
- double * /*warped_position_y*/) {
+ const float* /*mask*/,
+ float* /*patch*/,
+ double* /*warped_position_x*/,
+ double* /*warped_position_y*/) {
/* TODO(sergey): implement */
}
-void libmv_samplePlanarPatchByte(const unsigned char * /*image*/,
+void libmv_samplePlanarPatchByte(const unsigned char* /*image*/,
int /*width*/,
int /*height*/,
int /*channels*/,
- const double * /*xs*/,
- const double * /*ys*/,
- int /*num_samples_x*/, int /*num_samples_y*/,
- const float * /*mask*/,
- unsigned char * /*patch*/,
- double * /*warped_position_x*/,
- double * /*warped_position_y*/) {
+ const double* /*xs*/,
+ const double* /*ys*/,
+ int /*num_samples_x*/,
+ int /*num_samples_y*/,
+ const float* /*mask*/,
+ unsigned char* /*patch*/,
+ double* /*warped_position_x*/,
+ double* /*warped_position_y*/) {
/* TODO(sergey): implement */
}
-void libmv_floatImageDestroy(libmv_FloatImage* /*image*/)
-{
+void libmv_floatImageDestroy(libmv_FloatImage* /*image*/) {
}
/* ************ Tracks ************ */
-libmv_Tracks *libmv_tracksNew(void) {
+libmv_Tracks* libmv_tracksNew(void) {
return NULL;
}
-void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/,
+void libmv_tracksInsert(libmv_Tracks* /*libmv_tracks*/,
int /*image*/,
int /*track*/,
double /*x*/,
@@ -108,152 +108,152 @@ void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/,
double /*weight*/) {
}
-void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) {
+void libmv_tracksDestroy(libmv_Tracks* /*libmv_tracks*/) {
}
/* ************ Reconstruction solver ************ */
-libmv_Reconstruction *libmv_solveReconstruction(
- const libmv_Tracks * /*libmv_tracks*/,
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
- libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
+libmv_Reconstruction* libmv_solveReconstruction(
+ const libmv_Tracks* /*libmv_tracks*/,
+ const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/,
+ libmv_ReconstructionOptions* /*libmv_reconstruction_options*/,
reconstruct_progress_update_cb /*progress_update_callback*/,
- void * /*callback_customdata*/) {
+ void* /*callback_customdata*/) {
return NULL;
}
-libmv_Reconstruction *libmv_solveModal(
- const libmv_Tracks * /*libmv_tracks*/,
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
- const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
+libmv_Reconstruction* libmv_solveModal(
+ const libmv_Tracks* /*libmv_tracks*/,
+ const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/,
+ const libmv_ReconstructionOptions* /*libmv_reconstruction_options*/,
reconstruct_progress_update_cb /*progress_update_callback*/,
- void * /*callback_customdata*/) {
+ void* /*callback_customdata*/) {
return NULL;
}
-int libmv_reconstructionIsValid(libmv_Reconstruction * /*libmv_reconstruction*/) {
+int libmv_reconstructionIsValid(
+ libmv_Reconstruction* /*libmv_reconstruction*/) {
return 0;
}
int libmv_reprojectionPointForTrack(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
+ const libmv_Reconstruction* /*libmv_reconstruction*/,
int /*track*/,
double /*pos*/[3]) {
return 0;
}
double libmv_reprojectionErrorForTrack(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
- int /*track*/) {
+ const libmv_Reconstruction* /*libmv_reconstruction*/, int /*track*/) {
return 0.0;
}
double libmv_reprojectionErrorForImage(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
- int /*image*/) {
+ const libmv_Reconstruction* /*libmv_reconstruction*/, int /*image*/) {
return 0.0;
}
int libmv_reprojectionCameraForImage(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
+ const libmv_Reconstruction* /*libmv_reconstruction*/,
int /*image*/,
double /*mat*/[4][4]) {
return 0;
}
double libmv_reprojectionError(
- const libmv_Reconstruction * /*libmv_reconstruction*/) {
+ const libmv_Reconstruction* /*libmv_reconstruction*/) {
return 0.0;
}
void libmv_reconstructionDestroy(
- struct libmv_Reconstruction * /*libmv_reconstruction*/) {
+ struct libmv_Reconstruction* /*libmv_reconstruction*/) {
}
/* ************ Feature detector ************ */
-libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/,
+libmv_Features* libmv_detectFeaturesByte(const unsigned char* /*image_buffer*/,
int /*width*/,
int /*height*/,
int /*channels*/,
- libmv_DetectOptions * /*options*/) {
+ libmv_DetectOptions* /*options*/) {
return NULL;
}
-struct libmv_Features *libmv_detectFeaturesFloat(
- const float * /*image_buffer*/,
+struct libmv_Features* libmv_detectFeaturesFloat(
+ const float* /*image_buffer*/,
int /*width*/,
int /*height*/,
int /*channels*/,
- libmv_DetectOptions * /*options*/) {
+ libmv_DetectOptions* /*options*/) {
return NULL;
}
-int libmv_countFeatures(const libmv_Features * /*libmv_features*/) {
+int libmv_countFeatures(const libmv_Features* /*libmv_features*/) {
return 0;
}
-void libmv_getFeature(const libmv_Features * /*libmv_features*/,
+void libmv_getFeature(const libmv_Features* /*libmv_features*/,
int /*number*/,
- double *x,
- double *y,
- double *score,
- double *size) {
+ double* x,
+ double* y,
+ double* score,
+ double* size) {
*x = 0.0;
*y = 0.0;
*score = 0.0;
*size = 0.0;
}
-void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) {
+void libmv_featuresDestroy(struct libmv_Features* /*libmv_features*/) {
}
/* ************ Camera intrinsics ************ */
-libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
- libmv_Reconstruction * /*libmv_reconstruction*/) {
+libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics(
+ libmv_Reconstruction* /*libmv_reconstruction*/) {
return NULL;
}
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) {
+libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew(
+ const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/) {
return NULL;
}
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
- const libmv_CameraIntrinsics * /*libmvIntrinsics*/) {
+libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy(
+ const libmv_CameraIntrinsics* /*libmvIntrinsics*/) {
return NULL;
}
void libmv_cameraIntrinsicsDestroy(
- libmv_CameraIntrinsics * /*libmvIntrinsics*/) {
+ libmv_CameraIntrinsics* /*libmvIntrinsics*/) {
}
void libmv_cameraIntrinsicsUpdate(
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
- libmv_CameraIntrinsics * /*libmv_intrinsics*/) {
+ const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/,
+ libmv_CameraIntrinsics* /*libmv_intrinsics*/) {
}
void libmv_cameraIntrinsicsSetThreads(
- libmv_CameraIntrinsics * /*libmv_intrinsics*/,
- int /*threads*/) {
+ libmv_CameraIntrinsics* /*libmv_intrinsics*/, int /*threads*/) {
}
void libmv_cameraIntrinsicsExtractOptions(
- const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
- libmv_CameraIntrinsicsOptions *camera_intrinsics_options) {
+ const libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions));
camera_intrinsics_options->focal_length = 1.0;
}
void libmv_cameraIntrinsicsUndistortByte(
- const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
- const unsigned char *source_image,
- int width, int height,
+ const libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ const unsigned char* source_image,
+ int width,
+ int height,
float /*overscan*/,
int channels,
- unsigned char *destination_image) {
- memcpy(destination_image, source_image,
+ unsigned char* destination_image) {
+ memcpy(destination_image,
+ source_image,
channels * width * height * sizeof(unsigned char));
}
@@ -265,19 +265,21 @@ void libmv_cameraIntrinsicsUndistortFloat(
float /*overscan*/,
int channels,
float* destination_image) {
- memcpy(destination_image, source_image,
+ memcpy(destination_image,
+ source_image,
channels * width * height * sizeof(float));
}
void libmv_cameraIntrinsicsDistortByte(
const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/,
- const unsigned char *source_image,
+ const unsigned char* source_image,
int width,
int height,
float /*overscan*/,
int channels,
- unsigned char *destination_image) {
- memcpy(destination_image, source_image,
+ unsigned char* destination_image) {
+ memcpy(destination_image,
+ source_image,
channels * width * height * sizeof(unsigned char));
}
@@ -289,7 +291,8 @@ void libmv_cameraIntrinsicsDistortFloat(
float /*overscan*/,
int channels,
float* destination_image) {
- memcpy(destination_image, source_image,
+ memcpy(destination_image,
+ source_image,
channels * width * height * sizeof(float));
}
@@ -315,8 +318,8 @@ void libmv_cameraIntrinsicsInvert(
*y1 = 0.0;
}
-void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2],
- /* const */ double (* /*x2*/)[2],
+void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*/*x1*/)[2],
+ /* const */ double (*/*x2*/)[2],
int /*num_points*/,
double H[3][3]) {
memset(H, 0, sizeof(double[3][3]));
@@ -327,45 +330,38 @@ void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2],
/* ************ autotrack ************ */
-libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/)
-{
+libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/) {
return NULL;
}
-void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/)
-{
+void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/) {
}
void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/,
- const libmv_AutoTrackOptions* /*options*/)
-{
+ const libmv_AutoTrackOptions* /*options*/) {
}
int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/,
const libmv_TrackRegionOptions* /*libmv_options*/,
- libmv_Marker * /*libmv_tracker_marker*/,
- libmv_TrackRegionResult* /*libmv_result*/)
-{
+ libmv_Marker* /*libmv_tracker_marker*/,
+ libmv_TrackRegionResult* /*libmv_result*/) {
return 0;
}
void libmv_autoTrackAddMarker(libmv_AutoTrack* /*libmv_autotrack*/,
- const libmv_Marker* /*libmv_marker*/)
-{
+ const libmv_Marker* /*libmv_marker*/) {
}
void libmv_autoTrackSetMarkers(libmv_AutoTrack* /*libmv_autotrack*/,
const libmv_Marker* /*libmv_marker-*/,
- size_t /*num_markers*/)
-{
+ size_t /*num_markers*/) {
}
int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/,
int /*clip*/,
int /*frame*/,
int /*track*/,
- libmv_Marker* /*libmv_marker*/)
-{
+ libmv_Marker* /*libmv_marker*/) {
return 0;
}
@@ -376,24 +372,20 @@ libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_GetImageCallback /*get_image_callback*/,
libmv_ReleaseImageCallback /*release_image_callback*/,
libmv_GetMaskForTrackCallback /*get_mask_for_track_callback*/,
- libmv_ReleaseMaskCallback /*release_mask_callback*/)
-{
+ libmv_ReleaseMaskCallback /*release_mask_callback*/) {
return NULL;
}
-void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/)
-{
+void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/) {
}
int64_t libmv_frameAccessorgetTransformKey(
- const libmv_FrameTransform * /*transform*/)
-{
+ const libmv_FrameTransform* /*transform*/) {
return 0;
}
-void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* /*transform*/,
- const libmv_FloatImage* /*input_image*/,
- libmv_FloatImage* /*output_image*/)
-{
+void libmv_frameAccessorgetTransformRun(
+ const libmv_FrameTransform* /*transform*/,
+ const libmv_FloatImage* /*input_image*/,
+ libmv_FloatImage* /*output_image*/) {
}
-
diff --git a/intern/libmv/intern/track_region.cc b/intern/libmv/intern/track_region.cc
index 2a3909c0ced..f434906407b 100644
--- a/intern/libmv/intern/track_region.cc
+++ b/intern/libmv/intern/track_region.cc
@@ -21,6 +21,7 @@
#include "intern/image.h"
#include "intern/utildefines.h"
#include "libmv/image/image.h"
+#include "libmv/logging/logging.h"
#include "libmv/tracking/track_region.h"
/* define this to generate PNG images with content of search areas
@@ -32,27 +33,53 @@
#undef DUMP_ALWAYS
using libmv::FloatImage;
+using libmv::TrackRegion;
using libmv::TrackRegionOptions;
using libmv::TrackRegionResult;
-using libmv::TrackRegion;
-void libmv_configureTrackRegionOptions(
- const libmv_TrackRegionOptions& options,
- TrackRegionOptions* track_region_options) {
- switch (options.motion_model) {
-#define LIBMV_CONVERT(the_model) \
- case TrackRegionOptions::the_model: \
- track_region_options->mode = TrackRegionOptions::the_model; \
- break;
+namespace {
+
+TrackRegionOptions::Direction convertDirection(
+ libmv_TrackRegionDirection direction) {
+ switch (direction) {
+ case LIBMV_TRACK_REGION_FORWARD: return TrackRegionOptions::FORWARD;
+ case LIBMV_TRACK_REGION_BACKWARD: return TrackRegionOptions::BACKWARD;
+ }
+
+ LOG(FATAL) << "Unhandled tracking direction " << direction
+ << ", should never happen.";
+
+ return TrackRegionOptions::FORWARD;
+}
+
+TrackRegionOptions::Mode convertMotionModelToMode(int motion_model) {
+ switch (motion_model) {
+#define LIBMV_CONVERT(the_model) \
+ case TrackRegionOptions::the_model: return TrackRegionOptions::the_model;
+
LIBMV_CONVERT(TRANSLATION)
LIBMV_CONVERT(TRANSLATION_ROTATION)
LIBMV_CONVERT(TRANSLATION_SCALE)
LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE)
LIBMV_CONVERT(AFFINE)
LIBMV_CONVERT(HOMOGRAPHY)
+
#undef LIBMV_CONVERT
}
+ LOG(FATAL) << "Unhandled motion model " << motion_model
+ << ", should never happen.";
+
+ return TrackRegionOptions::TRANSLATION;
+}
+
+} // namespace
+
+void libmv_configureTrackRegionOptions(
+ const libmv_TrackRegionOptions& options,
+ TrackRegionOptions* track_region_options) {
+ track_region_options->direction = convertDirection(options.direction);
+ track_region_options->mode = convertMotionModelToMode(options.motion_model);
track_region_options->minimum_correlation = options.minimum_correlation;
track_region_options->max_iterations = options.num_iterations;
track_region_options->sigma = options.sigma;
@@ -66,7 +93,8 @@ void libmv_configureTrackRegionOptions(
* so disabling for now for until proper prediction model is landed.
*
* The thing is, currently blender sends input coordinates as the guess to
- * region tracker and in case of fast motion such an early out ruins the track.
+ * region tracker and in case of fast motion such an early out ruins the
+ * track.
*/
track_region_options->attempt_refine_before_brute = false;
track_region_options->use_normalized_intensities = options.use_normalization;
@@ -74,7 +102,7 @@ void libmv_configureTrackRegionOptions(
void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result,
libmv_TrackRegionResult* result) {
- result->termination = (int) track_region_result.termination;
+ result->termination = (int)track_region_result.termination;
result->termination_reason = "";
result->correlation = track_region_result.correlation;
}
@@ -108,33 +136,27 @@ int libmv_trackRegion(const libmv_TrackRegionOptions* options,
libmv_configureTrackRegionOptions(*options, &track_region_options);
if (options->image1_mask) {
- libmv_floatBufferToFloatImage(options->image1_mask,
- image1_width,
- image1_height,
- 1,
- &image1_mask);
+ libmv_floatBufferToFloatImage(
+ options->image1_mask, image1_width, image1_height, 1, &image1_mask);
track_region_options.image1_mask = &image1_mask;
}
// Convert from raw float buffers to libmv's FloatImage.
FloatImage old_patch, new_patch;
- libmv_floatBufferToFloatImage(image1,
- image1_width,
- image1_height,
- 1,
- &old_patch);
- libmv_floatBufferToFloatImage(image2,
- image2_width,
- image2_height,
- 1,
- &new_patch);
+ libmv_floatBufferToFloatImage(
+ image1, image1_width, image1_height, 1, &old_patch);
+ libmv_floatBufferToFloatImage(
+ image2, image2_width, image2_height, 1, &new_patch);
TrackRegionResult track_region_result;
- TrackRegion(old_patch, new_patch,
- xx1, yy1,
+ TrackRegion(old_patch,
+ new_patch,
+ xx1,
+ yy1,
track_region_options,
- xx2, yy2,
+ xx2,
+ yy2,
&track_region_result);
// Convert to floats for the blender api.
diff --git a/intern/libmv/intern/track_region.h b/intern/libmv/intern/track_region.h
index 48ae97a1c1a..2f10105ccd5 100644
--- a/intern/libmv/intern/track_region.h
+++ b/intern/libmv/intern/track_region.h
@@ -24,14 +24,20 @@
extern "C" {
#endif
+typedef enum libmv_TrackRegionDirection {
+ LIBMV_TRACK_REGION_FORWARD,
+ LIBMV_TRACK_REGION_BACKWARD,
+} libmv_TrackRegionDirection;
+
typedef struct libmv_TrackRegionOptions {
+ libmv_TrackRegionDirection direction;
int motion_model;
int num_iterations;
int use_brute;
int use_normalization;
double minimum_correlation;
double sigma;
- float *image1_mask;
+ float* image1_mask;
} libmv_TrackRegionOptions;
typedef struct libmv_TrackRegionResult {
@@ -42,9 +48,9 @@ typedef struct libmv_TrackRegionResult {
#ifdef __cplusplus
namespace libmv {
- struct TrackRegionOptions;
- struct TrackRegionResult;
-}
+struct TrackRegionOptions;
+struct TrackRegionResult;
+} // namespace libmv
void libmv_configureTrackRegionOptions(
const libmv_TrackRegionOptions& options,
libmv::TrackRegionOptions* track_region_options);
diff --git a/intern/libmv/intern/tracks.cc b/intern/libmv/intern/tracks.cc
index 0ca5a31796b..146908d6db5 100644
--- a/intern/libmv/intern/tracks.cc
+++ b/intern/libmv/intern/tracks.cc
@@ -28,18 +28,18 @@ using libmv::Tracks;
libmv_Tracks* libmv_tracksNew(void) {
Tracks* tracks = LIBMV_OBJECT_NEW(Tracks);
- return (libmv_Tracks*) tracks;
+ return (libmv_Tracks*)tracks;
}
void libmv_tracksDestroy(libmv_Tracks* libmv_tracks) {
LIBMV_OBJECT_DELETE(libmv_tracks, Tracks);
}
-void libmv_tracksInsert(libmv_Tracks *libmv_tracks,
+void libmv_tracksInsert(libmv_Tracks* libmv_tracks,
int image,
int track,
double x,
double y,
double weight) {
- ((Tracks *) libmv_tracks)->Insert(image, track, x, y, weight);
+ ((Tracks*)libmv_tracks)->Insert(image, track, x, y, weight);
}
diff --git a/intern/libmv/intern/tracksN.cc b/intern/libmv/intern/tracksN.cc
index 1441d8a2066..c7ffb13a386 100644
--- a/intern/libmv/intern/tracksN.cc
+++ b/intern/libmv/intern/tracksN.cc
@@ -25,8 +25,7 @@
using mv::Marker;
using mv::Tracks;
-void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker,
- Marker *marker) {
+void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, Marker* marker) {
marker->clip = libmv_marker.clip;
marker->frame = libmv_marker.frame;
marker->track = libmv_marker.track;
@@ -41,17 +40,16 @@ void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker,
marker->search_region.max(0) = libmv_marker.search_region_max[0];
marker->search_region.max(1) = libmv_marker.search_region_max[1];
marker->weight = libmv_marker.weight;
- marker->source = (Marker::Source) libmv_marker.source;
- marker->status = (Marker::Status) libmv_marker.status;
+ marker->source = (Marker::Source)libmv_marker.source;
+ marker->status = (Marker::Status)libmv_marker.status;
marker->reference_clip = libmv_marker.reference_clip;
marker->reference_frame = libmv_marker.reference_frame;
- marker->model_type = (Marker::ModelType) libmv_marker.model_type;
+ marker->model_type = (Marker::ModelType)libmv_marker.model_type;
marker->model_id = libmv_marker.model_id;
marker->disabled_channels = libmv_marker.disabled_channels;
}
-void libmv_markerToApiMarker(const Marker& marker,
- libmv_Marker *libmv_marker) {
+void libmv_markerToApiMarker(const Marker& marker, libmv_Marker* libmv_marker) {
libmv_marker->clip = marker.clip;
libmv_marker->frame = marker.frame;
libmv_marker->track = marker.track;
@@ -66,11 +64,11 @@ void libmv_markerToApiMarker(const Marker& marker,
libmv_marker->search_region_max[0] = marker.search_region.max(0);
libmv_marker->search_region_max[1] = marker.search_region.max(1);
libmv_marker->weight = marker.weight;
- libmv_marker->source = (libmv_MarkerSource) marker.source;
- libmv_marker->status = (libmv_MarkerStatus) marker.status;
+ libmv_marker->source = (libmv_MarkerSource)marker.source;
+ libmv_marker->status = (libmv_MarkerStatus)marker.status;
libmv_marker->reference_clip = marker.reference_clip;
libmv_marker->reference_frame = marker.reference_frame;
- libmv_marker->model_type = (libmv_MarkerModelType) marker.model_type;
+ libmv_marker->model_type = (libmv_MarkerModelType)marker.model_type;
libmv_marker->model_id = marker.model_id;
libmv_marker->disabled_channels = marker.disabled_channels;
}
@@ -78,7 +76,7 @@ void libmv_markerToApiMarker(const Marker& marker,
libmv_TracksN* libmv_tracksNewN(void) {
Tracks* tracks = LIBMV_OBJECT_NEW(Tracks);
- return (libmv_TracksN*) tracks;
+ return (libmv_TracksN*)tracks;
}
void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks) {
@@ -89,7 +87,7 @@ void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks,
const libmv_Marker* libmv_marker) {
Marker marker;
libmv_apiMarkerToMarker(*libmv_marker, &marker);
- ((Tracks*) libmv_tracks)->AddMarker(marker);
+ ((Tracks*)libmv_tracks)->AddMarker(marker);
}
void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks,
@@ -98,7 +96,7 @@ void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks,
int track,
libmv_Marker* libmv_marker) {
Marker marker;
- ((Tracks*) libmv_tracks)->GetMarker(clip, frame, track, &marker);
+ ((Tracks*)libmv_tracks)->GetMarker(clip, frame, track, &marker);
libmv_markerToApiMarker(marker, libmv_marker);
}
@@ -106,26 +104,25 @@ void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks,
int clip,
int frame,
int track) {
- ((Tracks *) libmv_tracks)->RemoveMarker(clip, frame, track);
+ ((Tracks*)libmv_tracks)->RemoveMarker(clip, frame, track);
}
-void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks,
- int track) {
- ((Tracks *) libmv_tracks)->RemoveMarkersForTrack(track);
+void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, int track) {
+ ((Tracks*)libmv_tracks)->RemoveMarkersForTrack(track);
}
int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks) {
- return ((Tracks*) libmv_tracks)->MaxClip();
+ return ((Tracks*)libmv_tracks)->MaxClip();
}
int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip) {
- return ((Tracks*) libmv_tracks)->MaxFrame(clip);
+ return ((Tracks*)libmv_tracks)->MaxFrame(clip);
}
int libmv_tracksMaxTrackN(libmv_TracksN* libmv_tracks) {
- return ((Tracks*) libmv_tracks)->MaxTrack();
+ return ((Tracks*)libmv_tracks)->MaxTrack();
}
int libmv_tracksNumMarkersN(libmv_TracksN* libmv_tracks) {
- return ((Tracks*) libmv_tracks)->NumMarkers();
+ return ((Tracks*)libmv_tracks)->NumMarkers();
}
diff --git a/intern/libmv/intern/tracksN.h b/intern/libmv/intern/tracksN.h
index 9363d34bed7..b5d1f9753e0 100644
--- a/intern/libmv/intern/tracksN.h
+++ b/intern/libmv/intern/tracksN.h
@@ -79,20 +79,19 @@ typedef struct libmv_Marker {
#ifdef __cplusplus
namespace mv {
- struct Marker;
+struct Marker;
}
void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker,
- mv::Marker *marker);
+ mv::Marker* marker);
void libmv_markerToApiMarker(const mv::Marker& marker,
- libmv_Marker *libmv_marker);
+ libmv_Marker* libmv_marker);
#endif
libmv_TracksN* libmv_tracksNewN(void);
void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks);
-
void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks,
const libmv_Marker* libmv_marker);
@@ -107,8 +106,7 @@ void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks,
int frame,
int track);
-void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks,
- int track);
+void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, int track);
int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks);
int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip);
diff --git a/intern/libmv/intern/utildefines.h b/intern/libmv/intern/utildefines.h
index d76d32f9c4d..052052a1d76 100644
--- a/intern/libmv/intern/utildefines.h
+++ b/intern/libmv/intern/utildefines.h
@@ -30,27 +30,33 @@
# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW
# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
-# define LIBMV_STRUCT_NEW(type, count) \
- (type*)MEM_mallocN(sizeof(type) * count, __func__)
+# define LIBMV_STRUCT_NEW(type, count) \
+ (type*)MEM_mallocN(sizeof(type) * count, __func__)
# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what)
#else
// Need this to keep libmv-capi potentially standalone.
# if defined __GNUC__ || defined __sun
-# define LIBMV_OBJECT_NEW(type, args ...) \
- new(malloc(sizeof(type))) type(args)
+# define LIBMV_OBJECT_NEW(type, args...) \
+ new (malloc(sizeof(type))) type(args)
# else
-# define LIBMV_OBJECT_NEW(type, ...) \
- new(malloc(sizeof(type))) type(__VA_ARGS__)
-#endif
-# define LIBMV_OBJECT_DELETE(what, type) \
- { \
- if (what) { \
- ((type*)(what))->~type(); \
- free(what); \
- } \
- } (void)0
+# define LIBMV_OBJECT_NEW(type, ...) \
+ new (malloc(sizeof(type))) type(__VA_ARGS__)
+# endif
+# define LIBMV_OBJECT_DELETE(what, type) \
+ { \
+ if (what) { \
+ ((type*)(what))->~type(); \
+ free(what); \
+ } \
+ } \
+ (void)0
# define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count)
-# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0
+# define LIBMV_STRUCT_DELETE(what) \
+ { \
+ if (what) \
+ free(what); \
+ } \
+ (void)0
#endif
#endif // LIBMV_C_API_UTILDEFINES_H_
diff --git a/intern/libmv/libmv/autotrack/autotrack.cc b/intern/libmv/libmv/autotrack/autotrack.cc
index 3b0a762178a..afdf48912e5 100644
--- a/intern/libmv/libmv/autotrack/autotrack.cc
+++ b/intern/libmv/libmv/autotrack/autotrack.cc
@@ -21,9 +21,9 @@
// Author: mierle@gmail.com (Keir Mierle)
#include "libmv/autotrack/autotrack.h"
-#include "libmv/autotrack/quad.h"
#include "libmv/autotrack/frame_accessor.h"
#include "libmv/autotrack/predict_tracks.h"
+#include "libmv/autotrack/quad.h"
#include "libmv/base/scoped_ptr.h"
#include "libmv/logging/logging.h"
#include "libmv/numeric/numeric.h"
@@ -35,34 +35,30 @@ namespace {
class DisableChannelsTransform : public FrameAccessor::Transform {
public:
DisableChannelsTransform(int disabled_channels)
- : disabled_channels_(disabled_channels) { }
+ : disabled_channels_(disabled_channels) {}
- int64_t key() const {
- return disabled_channels_;
- }
+ int64_t key() const { return disabled_channels_; }
void run(const FloatImage& input, FloatImage* output) const {
- bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0,
+ bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0,
disable_green = (disabled_channels_ & Marker::CHANNEL_G) != 0,
- disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0;
+ disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0;
- LG << "Disabling channels: "
- << (disable_red ? "R " : "")
- << (disable_green ? "G " : "")
- << (disable_blue ? "B" : "");
+ LG << "Disabling channels: " << (disable_red ? "R " : "")
+ << (disable_green ? "G " : "") << (disable_blue ? "B" : "");
// It's important to rescale the resultappropriately so that e.g. if only
// blue is selected, it's not zeroed out.
- float scale = (disable_red ? 0.0f : 0.2126f) +
+ float scale = (disable_red ? 0.0f : 0.2126f) +
(disable_green ? 0.0f : 0.7152f) +
- (disable_blue ? 0.0f : 0.0722f);
+ (disable_blue ? 0.0f : 0.0722f);
output->Resize(input.Height(), input.Width(), 1);
for (int y = 0; y < input.Height(); y++) {
for (int x = 0; x < input.Width(); x++) {
- float r = disable_red ? 0.0f : input(y, x, 0);
+ float r = disable_red ? 0.0f : input(y, x, 0);
float g = disable_green ? 0.0f : input(y, x, 1);
- float b = disable_blue ? 0.0f : input(y, x, 2);
+ float b = disable_blue ? 0.0f : input(y, x, 2);
(*output)(y, x, 0) = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
}
}
@@ -73,7 +69,7 @@ class DisableChannelsTransform : public FrameAccessor::Transform {
int disabled_channels_;
};
-template<typename QuadT, typename ArrayT>
+template <typename QuadT, typename ArrayT>
void QuadToArrays(const QuadT& quad, ArrayT* x, ArrayT* y) {
for (int i = 0; i < 4; ++i) {
x[i] = quad.coordinates(i, 0);
@@ -115,11 +111,20 @@ FrameAccessor::Key GetMaskForMarker(const Marker& marker,
FrameAccessor* frame_accessor,
FloatImage* mask) {
Region region = marker.search_region.Rounded();
- return frame_accessor->GetMaskForTrack(marker.clip,
- marker.frame,
- marker.track,
- &region,
- mask);
+ return frame_accessor->GetMaskForTrack(
+ marker.clip, marker.frame, marker.track, &region, mask);
+}
+
+PredictDirection getPredictDirection(const TrackRegionOptions* track_options) {
+ switch (track_options->direction) {
+ case TrackRegionOptions::FORWARD: return PredictDirection::FORWARD;
+ case TrackRegionOptions::BACKWARD: return PredictDirection::BACKWARD;
+ }
+
+ LOG(FATAL) << "Unhandled tracking direction " << track_options->direction
+ << ", should never happen.";
+
+ return PredictDirection::AUTO;
}
} // namespace
@@ -128,8 +133,9 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
TrackRegionResult* result,
const TrackRegionOptions* track_options) {
// Try to predict the location of the second marker.
+ const PredictDirection predict_direction = getPredictDirection(track_options);
bool predicted_position = false;
- if (PredictMarkerPosition(tracks_, tracked_marker)) {
+ if (PredictMarkerPosition(tracks_, predict_direction, tracked_marker)) {
LG << "Successfully predicted!";
predicted_position = true;
} else {
@@ -152,23 +158,20 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
// TODO(keir): Technically this could take a smaller slice from the source
// image instead of taking one the size of the search window.
FloatImage reference_image;
- FrameAccessor::Key reference_key = GetImageForMarker(reference_marker,
- frame_accessor_,
- &reference_image);
+ FrameAccessor::Key reference_key =
+ GetImageForMarker(reference_marker, frame_accessor_, &reference_image);
if (!reference_key) {
LG << "Couldn't get frame for reference marker: " << reference_marker;
return false;
}
FloatImage reference_mask;
- FrameAccessor::Key reference_mask_key = GetMaskForMarker(reference_marker,
- frame_accessor_,
- &reference_mask);
+ FrameAccessor::Key reference_mask_key =
+ GetMaskForMarker(reference_marker, frame_accessor_, &reference_mask);
FloatImage tracked_image;
- FrameAccessor::Key tracked_key = GetImageForMarker(*tracked_marker,
- frame_accessor_,
- &tracked_image);
+ FrameAccessor::Key tracked_key =
+ GetImageForMarker(*tracked_marker, frame_accessor_, &tracked_image);
if (!tracked_key) {
frame_accessor_->ReleaseImage(reference_key);
LG << "Couldn't get frame for tracked marker: " << tracked_marker;
@@ -191,9 +194,11 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
local_track_region_options.attempt_refine_before_brute = predicted_position;
TrackRegion(reference_image,
tracked_image,
- x1, y1,
+ x1,
+ y1,
local_track_region_options,
- x2, y2,
+ x2,
+ y2,
result);
// Copy results over the tracked marker.
@@ -208,7 +213,7 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
tracked_marker->search_region.Offset(delta);
tracked_marker->source = Marker::TRACKED;
tracked_marker->status = Marker::UNKNOWN;
- tracked_marker->reference_clip = reference_marker.clip;
+ tracked_marker->reference_clip = reference_marker.clip;
tracked_marker->reference_frame = reference_marker.frame;
// Release the images and masks from the accessor cache.
@@ -230,7 +235,9 @@ void AutoTrack::SetMarkers(vector<Marker>* markers) {
tracks_.SetMarkers(markers);
}
-bool AutoTrack::GetMarker(int clip, int frame, int track,
+bool AutoTrack::GetMarker(int clip,
+ int frame,
+ int track,
Marker* markers) const {
return tracks_.GetMarker(clip, frame, track, markers);
}
@@ -242,7 +249,8 @@ void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) {
vector<Marker> previous_frame_markers;
// Q: How to decide track #s when detecting?
// Q: How to match markers from previous frame? set of prev frame tracks?
- // Q: How to decide what markers should get tracked and which ones should not?
+ // Q: How to decide what markers should get tracked and which ones should
+ // not?
for (int frame = 0; frame < num_frames; ++frame) {
if (Cancelled()) {
LG << "Got cancel message while detecting and tracking...";
@@ -271,8 +279,7 @@ void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) {
for (int i = 0; i < this_frame_markers.size(); ++i) {
tracks_in_this_frame.push_back(this_frame_markers[i].track);
}
- std::sort(tracks_in_this_frame.begin(),
- tracks_in_this_frame.end());
+ std::sort(tracks_in_this_frame.begin(), tracks_in_this_frame.end());
// Find tracks in the previous frame that are not in this one.
vector<Marker*> previous_frame_markers_to_track;
diff --git a/intern/libmv/libmv/autotrack/autotrack.h b/intern/libmv/libmv/autotrack/autotrack.h
index 1d7422f54e7..281766f600f 100644
--- a/intern/libmv/libmv/autotrack/autotrack.h
+++ b/intern/libmv/libmv/autotrack/autotrack.h
@@ -23,8 +23,8 @@
#ifndef LIBMV_AUTOTRACK_AUTOTRACK_H_
#define LIBMV_AUTOTRACK_AUTOTRACK_H_
-#include "libmv/autotrack/tracks.h"
#include "libmv/autotrack/region.h"
+#include "libmv/autotrack/tracks.h"
#include "libmv/tracking/track_region.h"
namespace libmv {
@@ -74,15 +74,14 @@ class AutoTrack {
Region search_region;
};
- AutoTrack(FrameAccessor* frame_accessor)
- : frame_accessor_(frame_accessor) {}
+ AutoTrack(FrameAccessor* frame_accessor) : frame_accessor_(frame_accessor) {}
// Marker manipulation.
// Clip manipulation.
// Set the number of clips. These clips will get accessed from the frame
// accessor, matches between frames found, and a reconstruction created.
- //void SetNumFrames(int clip, int num_frames);
+ // void SetNumFrames(int clip, int num_frames);
// Tracking & Matching
@@ -90,7 +89,7 @@ class AutoTrack {
// Caller maintains ownership of *result and *tracked_marker.
bool TrackMarker(Marker* tracked_marker,
TrackRegionResult* result,
- const TrackRegionOptions* track_options=NULL);
+ const TrackRegionOptions* track_options = NULL);
// Wrapper around Tracks API; however these may add additional processing.
void AddMarker(const Marker& tracked_marker);
@@ -99,36 +98,36 @@ class AutoTrack {
// TODO(keir): Implement frame matching! This could be very cool for loop
// closing and connecting across clips.
- //void MatchFrames(int clip1, int frame1, int clip2, int frame2) {}
+ // void MatchFrames(int clip1, int frame1, int clip2, int frame2) {}
// Wrapper around the Reconstruction API.
// Returns the new ID.
int AddCameraIntrinsics(CameraIntrinsics* intrinsics) {
- (void) intrinsics;
+ (void)intrinsics;
return 0;
} // XXX
int SetClipIntrinsics(int clip, int intrinsics) {
- (void) clip;
- (void) intrinsics;
+ (void)clip;
+ (void)intrinsics;
return 0;
- } // XXX
+ } // XXX
enum Motion {
GENERAL_CAMERA_MOTION,
TRIPOD_CAMERA_MOTION,
};
int SetClipMotion(int clip, Motion motion) {
- (void) clip;
- (void) motion;
+ (void)clip;
+ (void)motion;
return 0;
- } // XXX
+ } // XXX
// Decide what to refine for the given intrinsics. bundle_options is from
// bundle.h (e.g. BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL_K1).
void SetIntrinsicsRefine(int intrinsics, int bundle_options) {
- (void) intrinsics;
- (void) bundle_options;
- } // XXX
+ (void)intrinsics;
+ (void)bundle_options;
+ } // XXX
// Keyframe read/write.
struct ClipFrame {
@@ -150,20 +149,19 @@ class AutoTrack {
};
void DetectAndTrack(const DetectAndTrackOptions& options);
- struct DetectFeaturesInFrameOptions {
- };
- void DetectFeaturesInFrame(int clip, int frame,
- const DetectFeaturesInFrameOptions* options=NULL) {
- (void) clip;
- (void) frame;
- (void) options;
- } // XXX
+ struct DetectFeaturesInFrameOptions {};
+ void DetectFeaturesInFrame(
+ int clip, int frame, const DetectFeaturesInFrameOptions* options = NULL) {
+ (void)clip;
+ (void)frame;
+ (void)options;
+ } // XXX
// Does not take ownership of the given listener, but keeps a reference to it.
- void AddListener(OperationListener* listener) {(void) listener;} // XXX
+ void AddListener(OperationListener* listener) { (void)listener; } // XXX
// Create the initial reconstruction,
- //void FindInitialReconstruction();
+ // void FindInitialReconstruction();
// State machine
//
@@ -202,17 +200,17 @@ class AutoTrack {
bool Cancelled() { return false; }
Tracks tracks_; // May be normalized camera coordinates or raw pixels.
- //Reconstruction reconstruction_;
+ // Reconstruction reconstruction_;
// TODO(keir): Add the motion models here.
- //vector<MotionModel> motion_models_;
+ // vector<MotionModel> motion_models_;
// TODO(keir): Should num_clips and num_frames get moved to FrameAccessor?
// TODO(keir): What about masking for clips and frames to prevent various
// things like reconstruction or tracking from happening on certain frames?
FrameAccessor* frame_accessor_;
- //int num_clips_;
- //vector<int> num_frames_; // Indexed by clip.
+ // int num_clips_;
+ // vector<int> num_frames_; // Indexed by clip.
// The intrinsics for each clip, assuming each clip has fixed intrinsics.
// TODO(keir): Decide what the semantics should be for varying focal length.
diff --git a/intern/libmv/libmv/autotrack/frame_accessor.h b/intern/libmv/libmv/autotrack/frame_accessor.h
index cfad9ca71ff..e9308dc400a 100644
--- a/intern/libmv/libmv/autotrack/frame_accessor.h
+++ b/intern/libmv/libmv/autotrack/frame_accessor.h
@@ -41,7 +41,7 @@ using libmv::FloatImage;
// implementations to cache filtered image pieces).
struct FrameAccessor {
struct Transform {
- virtual ~Transform() { }
+ virtual ~Transform() {}
// The key should depend on the transform arguments. Must be non-zero.
virtual int64_t key() const = 0;
@@ -50,10 +50,7 @@ struct FrameAccessor {
virtual void run(const FloatImage& input, FloatImage* output) const = 0;
};
- enum InputMode {
- MONO,
- RGBA
- };
+ enum InputMode { MONO, RGBA };
typedef void* Key;
@@ -100,6 +97,6 @@ struct FrameAccessor {
virtual int NumFrames(int clip) = 0;
};
-} // namespace libmv
+} // namespace mv
#endif // LIBMV_AUTOTRACK_FRAME_ACCESSOR_H_
diff --git a/intern/libmv/libmv/autotrack/marker.h b/intern/libmv/libmv/autotrack/marker.h
index bb803313af8..29e163c0446 100644
--- a/intern/libmv/libmv/autotrack/marker.h
+++ b/intern/libmv/libmv/autotrack/marker.h
@@ -57,23 +57,19 @@ struct Marker {
float weight;
enum Source {
- MANUAL, // The user placed this marker manually.
- DETECTED, // A keypoint detector found this point.
- TRACKED, // The tracking algorithm placed this marker.
- MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this.
- PREDICTED, // A motion model predicted this marker. This is needed for
- // handling occlusions in some cases where an imaginary marker
- // is placed to keep camera motion smooth.
+ MANUAL, // The user placed this marker manually.
+ DETECTED, // A keypoint detector found this point.
+ TRACKED, // The tracking algorithm placed this marker.
+ MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this.
+ PREDICTED, // A motion model predicted this marker. This is needed for
+ // handling occlusions in some cases where an imaginary marker
+ // is placed to keep camera motion smooth.
};
Source source;
// Markers may be inliers or outliers if the tracking fails; this allows
// visualizing the markers in the image.
- enum Status {
- UNKNOWN,
- INLIER,
- OUTLIER
- };
+ enum Status { UNKNOWN, INLIER, OUTLIER };
Status status;
// When doing correlation tracking, where to search in the current frame for
@@ -90,12 +86,7 @@ struct Marker {
// another primitive (a rectangular prisim). This captures the information
// needed to say that for example a collection of markers belongs to model #2
// (and model #2 is a plane).
- enum ModelType {
- POINT,
- PLANE,
- LINE,
- CUBE
- };
+ enum ModelType { POINT, PLANE, LINE, CUBE };
ModelType model_type;
// The model ID this track (e.g. the second model, which is a plane).
@@ -114,7 +105,7 @@ struct Marker {
int disabled_channels;
// Offset everything (center, patch, search) by the given delta.
- template<typename T>
+ template <typename T>
void Offset(const T& offset) {
center += offset.template cast<float>();
patch.coordinates.rowwise() += offset.template cast<int>();
@@ -122,19 +113,15 @@ struct Marker {
}
// Shift the center to the given new position (and patch, search).
- template<typename T>
+ template <typename T>
void SetPosition(const T& new_center) {
Offset(new_center - center);
}
};
inline std::ostream& operator<<(std::ostream& out, const Marker& marker) {
- out << "{"
- << marker.clip << ", "
- << marker.frame << ", "
- << marker.track << ", ("
- << marker.center.x() << ", "
- << marker.center.y() << ")"
+ out << "{" << marker.clip << ", " << marker.frame << ", " << marker.track
+ << ", (" << marker.center.x() << ", " << marker.center.y() << ")"
<< "}";
return out;
}
diff --git a/intern/libmv/libmv/autotrack/model.h b/intern/libmv/libmv/autotrack/model.h
index 1165281cdac..e79d38b742b 100644
--- a/intern/libmv/libmv/autotrack/model.h
+++ b/intern/libmv/libmv/autotrack/model.h
@@ -23,18 +23,13 @@
#ifndef LIBMV_AUTOTRACK_MODEL_H_
#define LIBMV_AUTOTRACK_MODEL_H_
-#include "libmv/numeric/numeric.h"
#include "libmv/autotrack/quad.h"
+#include "libmv/numeric/numeric.h"
namespace mv {
struct Model {
- enum ModelType {
- POINT,
- PLANE,
- LINE,
- CUBE
- };
+ enum ModelType { POINT, PLANE, LINE, CUBE };
// ???
};
diff --git a/intern/libmv/libmv/autotrack/predict_tracks.cc b/intern/libmv/libmv/autotrack/predict_tracks.cc
index 3786c1b9a3b..f3411066a07 100644
--- a/intern/libmv/libmv/autotrack/predict_tracks.cc
+++ b/intern/libmv/libmv/autotrack/predict_tracks.cc
@@ -20,8 +20,8 @@
//
// Author: mierle@gmail.com (Keir Mierle)
-#include "libmv/autotrack/marker.h"
#include "libmv/autotrack/predict_tracks.h"
+#include "libmv/autotrack/marker.h"
#include "libmv/autotrack/tracks.h"
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
@@ -31,8 +31,8 @@ namespace mv {
namespace {
-using libmv::vector;
using libmv::Vec2;
+using libmv::vector;
// Implied time delta between steps. Set empirically by tweaking and seeing
// what numbers did best at prediction.
@@ -57,6 +57,8 @@ const double dt = 3.8;
// For a typical system having constant velocity. This gives smooth-appearing
// predictions, but they are not always as accurate.
+//
+// clang-format off
const double velocity_state_transition_data[] = {
1, dt, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0,
@@ -65,10 +67,13 @@ const double velocity_state_transition_data[] = {
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1
};
+// clang-format on
#if 0
// This 3rd-order system also models acceleration. This makes for "jerky"
// predictions, but that tend to be more accurate.
+//
+// clang-format off
const double acceleration_state_transition_data[] = {
1, dt, dt*dt/2, 0, 0, 0,
0, 1, dt, 0, 0, 0,
@@ -77,9 +82,12 @@ const double acceleration_state_transition_data[] = {
0, 0, 0, 0, 1, dt,
0, 0, 0, 0, 0, 1
};
+// clang-format on
// This system (attempts) to add an angular velocity component. However, it's
// total junk.
+//
+// clang-format off
const double angular_state_transition_data[] = {
1, dt, -dt, 0, 0, 0, // Position x
0, 1, 0, 0, 0, 0, // Velocity x
@@ -88,17 +96,22 @@ const double angular_state_transition_data[] = {
0, 0, 0, 0, 1, 0, // Velocity y
0, 0, 0, 0, 0, 1 // Ignored
};
+// clang-format on
#endif
const double* state_transition_data = velocity_state_transition_data;
// Observation matrix.
+// clang-format off
const double observation_data[] = {
1., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 0.
};
+// clang-format on
// Process covariance.
+//
+// clang-format off
const double process_covariance_data[] = {
35, 0, 0, 0, 0, 0,
0, 5, 0, 0, 0, 0,
@@ -107,14 +120,19 @@ const double process_covariance_data[] = {
0, 0, 0, 0, 5, 0,
0, 0, 0, 0, 0, 5
};
+// clang-format on
// Process covariance.
const double measurement_covariance_data[] = {
- 0.01, 0.00,
- 0.00, 0.01,
+ 0.01,
+ 0.00,
+ 0.00,
+ 0.01,
};
// Initial covariance.
+//
+// clang-format off
const double initial_covariance_data[] = {
10, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0,
@@ -123,6 +141,7 @@ const double initial_covariance_data[] = {
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1
};
+// clang-format on
typedef mv::KalmanFilter<double, 6, 2> TrackerKalman;
@@ -138,7 +157,7 @@ bool OrderByFrameLessThan(const Marker* a, const Marker* b) {
}
return a->clip < b->clip;
}
- return a->frame < b-> frame;
+ return a->frame < b->frame;
}
// Predicted must be after the previous markers (in the frame numbering sense).
@@ -146,9 +165,9 @@ void RunPrediction(const vector<Marker*> previous_markers,
Marker* predicted_marker) {
TrackerKalman::State state;
state.mean << previous_markers[0]->center.x(), 0, 0,
- previous_markers[0]->center.y(), 0, 0;
- state.covariance = Eigen::Matrix<double, 6, 6, Eigen::RowMajor>(
- initial_covariance_data);
+ previous_markers[0]->center.y(), 0, 0;
+ state.covariance =
+ Eigen::Matrix<double, 6, 6, Eigen::RowMajor>(initial_covariance_data);
int current_frame = previous_markers[0]->frame;
int target_frame = predicted_marker->frame;
@@ -159,19 +178,18 @@ void RunPrediction(const vector<Marker*> previous_markers,
for (int i = 1; i < previous_markers.size(); ++i) {
// Step forward predicting the state until it is on the current marker.
int predictions = 0;
- for (;
- current_frame != previous_markers[i]->frame;
+ for (; current_frame != previous_markers[i]->frame;
current_frame += frame_delta) {
filter.Step(&state);
predictions++;
- LG << "Predicted point (frame " << current_frame << "): "
- << state.mean(0) << ", " << state.mean(3);
+ LG << "Predicted point (frame " << current_frame << "): " << state.mean(0)
+ << ", " << state.mean(3);
}
// Log the error -- not actually used, but interesting.
Vec2 error = previous_markers[i]->center.cast<double>() -
Vec2(state.mean(0), state.mean(3));
- LG << "Prediction error for " << predictions << " steps: ("
- << error.x() << ", " << error.y() << "); norm: " << error.norm();
+ LG << "Prediction error for " << predictions << " steps: (" << error.x()
+ << ", " << error.y() << "); norm: " << error.norm();
// Now that the state is predicted in the current frame, update the state
// based on the measurement from the current frame.
filter.Update(previous_markers[i]->center.cast<double>(),
@@ -184,8 +202,8 @@ void RunPrediction(const vector<Marker*> previous_markers,
// predict until the target frame.
for (; current_frame != target_frame; current_frame += frame_delta) {
filter.Step(&state);
- LG << "Final predicted point (frame " << current_frame << "): "
- << state.mean(0) << ", " << state.mean(3);
+ LG << "Final predicted point (frame " << current_frame
+ << "): " << state.mean(0) << ", " << state.mean(3);
}
// The x and y positions are at 0 and 3; ignore acceleration and velocity.
@@ -207,7 +225,9 @@ void RunPrediction(const vector<Marker*> previous_markers,
} // namespace
-bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) {
+bool PredictMarkerPosition(const Tracks& tracks,
+ const PredictDirection direction,
+ Marker* marker) {
// Get all markers for this clip and track.
vector<Marker> markers;
tracks.GetMarkersForTrackInClip(marker->clip, marker->track, &markers);
@@ -253,13 +273,13 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) {
} else if (insert_at != -1) {
// Found existing marker; scan before and after it.
forward_scan_begin = insert_at + 1;
- forward_scan_end = markers.size() - 1;;
+ forward_scan_end = markers.size() - 1;
backward_scan_begin = insert_at - 1;
backward_scan_end = 0;
} else {
// Didn't find existing marker but found an insertion point.
forward_scan_begin = insert_before;
- forward_scan_end = markers.size() - 1;;
+ forward_scan_end = markers.size() - 1;
backward_scan_begin = insert_before - 1;
backward_scan_end = 0;
}
@@ -272,9 +292,17 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) {
}
bool predict_forward = false;
- if (backward_scan_end <= backward_scan_begin) {
- // TODO(keir): Add smarter handling and detecting of consecutive frames!
- predict_forward = true;
+ switch (direction) {
+ case PredictDirection::AUTO:
+ if (backward_scan_end <= backward_scan_begin) {
+ // TODO(keir): Add smarter handling and detecting of consecutive frames!
+ predict_forward = true;
+ }
+ break;
+
+ case PredictDirection::FORWARD: predict_forward = true; break;
+
+ case PredictDirection::BACKWARD: predict_forward = false; break;
}
const int max_frames_to_predict_from = 20;
@@ -301,9 +329,8 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) {
return false;
}
LG << "Predicting backward";
- int predict_begin =
- std::min(forward_scan_begin + max_frames_to_predict_from,
- forward_scan_end);
+ int predict_begin = std::min(
+ forward_scan_begin + max_frames_to_predict_from, forward_scan_end);
int predict_end = forward_scan_begin;
vector<Marker*> previous_markers;
for (int i = predict_begin; i >= predict_end; --i) {
@@ -312,7 +339,6 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) {
RunPrediction(previous_markers, marker);
return false;
}
-
}
} // namespace mv
diff --git a/intern/libmv/libmv/autotrack/predict_tracks.h b/intern/libmv/libmv/autotrack/predict_tracks.h
index 0a176d08378..108846ebc96 100644
--- a/intern/libmv/libmv/autotrack/predict_tracks.h
+++ b/intern/libmv/libmv/autotrack/predict_tracks.h
@@ -28,9 +28,27 @@ namespace mv {
class Tracks;
struct Marker;
+enum class PredictDirection {
+ // Detect direction in which to predict marker position based on an existing
+ // Tracks context. Prediction will happen in the preferred direction of a
+ // missing information.
+ // If markers exists to the both sides of the given one the prediction
+ // direction is preferred to be forward.
+ AUTO,
+
+ // Predict position of the marker from the past to the future (used for
+ // forward tracking).
+ FORWARD,
+
+ // Predict position from the future to the past (used for backward tracking).
+ BACKWARD,
+};
+
// Predict the position of the given marker, and update it accordingly. The
// existing position will be overwritten.
-bool PredictMarkerPosition(const Tracks& tracks, Marker* marker);
+bool PredictMarkerPosition(const Tracks& tracks,
+ const PredictDirection direction,
+ Marker* marker);
} // namespace mv
diff --git a/intern/libmv/libmv/autotrack/predict_tracks_test.cc b/intern/libmv/libmv/autotrack/predict_tracks_test.cc
index f7c2c68d750..e45fcadd934 100644
--- a/intern/libmv/libmv/autotrack/predict_tracks_test.cc
+++ b/intern/libmv/libmv/autotrack/predict_tracks_test.cc
@@ -35,17 +35,15 @@ static void AddMarker(int frame, float x, float y, Tracks* tracks) {
marker.frame = frame;
marker.center.x() = x;
marker.center.y() = y;
- marker.patch.coordinates << x - 1, y - 1,
- x + 1, y - 1,
- x + 1, y + 1,
- x - 1, y + 1;
+ marker.patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1,
+ y + 1;
tracks->AddMarker(marker);
}
TEST(PredictMarkerPosition, EasyLinearMotion) {
Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
AddMarker(2, 3.0, 10.0, &tracks);
AddMarker(3, 4.0, 15.0, &tracks);
AddMarker(4, 5.0, 20.0, &tracks);
@@ -58,7 +56,7 @@ TEST(PredictMarkerPosition, EasyLinearMotion) {
predicted.track = 0;
predicted.frame = 8;
- PredictMarkerPosition(tracks, &predicted);
+ PredictMarkerPosition(tracks, PredictDirection::AUTO, &predicted);
double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
LG << "Got error: " << error;
EXPECT_LT(error, 0.1);
@@ -66,10 +64,8 @@ TEST(PredictMarkerPosition, EasyLinearMotion) {
// Check the patch coordinates as well.
double x = 9, y = 40.0;
Quad2Df expected_patch;
- expected_patch.coordinates << x - 1, y - 1,
- x + 1, y - 1,
- x + 1, y + 1,
- x - 1, y + 1;
+ expected_patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1,
+ y + 1;
error = (expected_patch.coordinates - predicted.patch.coordinates).norm();
LG << "Patch error: " << error;
@@ -78,8 +74,8 @@ TEST(PredictMarkerPosition, EasyLinearMotion) {
TEST(PredictMarkerPosition, EasyBackwardLinearMotion) {
Tracks tracks;
- AddMarker(8, 1.0, 0.0, &tracks);
- AddMarker(7, 2.0, 5.0, &tracks);
+ AddMarker(8, 1.0, 0.0, &tracks);
+ AddMarker(7, 2.0, 5.0, &tracks);
AddMarker(6, 3.0, 10.0, &tracks);
AddMarker(5, 4.0, 15.0, &tracks);
AddMarker(4, 5.0, 20.0, &tracks);
@@ -92,7 +88,7 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) {
predicted.track = 0;
predicted.frame = 0;
- PredictMarkerPosition(tracks, &predicted);
+ PredictMarkerPosition(tracks, PredictDirection::AUTO, &predicted);
LG << predicted;
double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
LG << "Got error: " << error;
@@ -101,10 +97,8 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) {
// Check the patch coordinates as well.
double x = 9.0, y = 40.0;
Quad2Df expected_patch;
- expected_patch.coordinates << x - 1, y - 1,
- x + 1, y - 1,
- x + 1, y + 1,
- x - 1, y + 1;
+ expected_patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1,
+ y + 1;
error = (expected_patch.coordinates - predicted.patch.coordinates).norm();
LG << "Patch error: " << error;
@@ -113,8 +107,8 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) {
TEST(PredictMarkerPosition, TwoFrameGap) {
Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
AddMarker(2, 3.0, 10.0, &tracks);
AddMarker(3, 4.0, 15.0, &tracks);
AddMarker(4, 5.0, 20.0, &tracks);
@@ -127,7 +121,7 @@ TEST(PredictMarkerPosition, TwoFrameGap) {
predicted.track = 0;
predicted.frame = 8;
- PredictMarkerPosition(tracks, &predicted);
+ PredictMarkerPosition(tracks, PredictDirection::AUTO, &predicted);
double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
LG << "Got error: " << error;
EXPECT_LT(error, 0.1);
@@ -135,8 +129,8 @@ TEST(PredictMarkerPosition, TwoFrameGap) {
TEST(PredictMarkerPosition, FourFrameGap) {
Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
AddMarker(2, 3.0, 10.0, &tracks);
AddMarker(3, 4.0, 15.0, &tracks);
// Missing frames 4, 5, 6, 7.
@@ -146,7 +140,7 @@ TEST(PredictMarkerPosition, FourFrameGap) {
predicted.track = 0;
predicted.frame = 8;
- PredictMarkerPosition(tracks, &predicted);
+ PredictMarkerPosition(tracks, PredictDirection::AUTO, &predicted);
double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
LG << "Got error: " << error;
EXPECT_LT(error, 2.0); // Generous error due to larger prediction window.
@@ -154,13 +148,13 @@ TEST(PredictMarkerPosition, FourFrameGap) {
TEST(PredictMarkerPosition, MultipleGaps) {
Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
AddMarker(2, 3.0, 10.0, &tracks);
// AddMarker(3, 4.0, 15.0, &tracks); // Note the 3-frame gap.
// AddMarker(4, 5.0, 20.0, &tracks);
// AddMarker(5, 6.0, 25.0, &tracks);
- AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement.
+ AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement.
// AddMarker(7, 8.0, 35.0, &tracks);
Marker predicted;
@@ -168,7 +162,7 @@ TEST(PredictMarkerPosition, MultipleGaps) {
predicted.track = 0;
predicted.frame = 8;
- PredictMarkerPosition(tracks, &predicted);
+ PredictMarkerPosition(tracks, PredictDirection::AUTO, &predicted);
double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
LG << "Got error: " << error;
EXPECT_LT(error, 1.0); // Generous error due to larger prediction window.
@@ -178,21 +172,21 @@ TEST(PredictMarkerPosition, MarkersInRandomOrder) {
Tracks tracks;
// This is the same as the easy, except that the tracks are randomly ordered.
- AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(0, 1.0, 0.0, &tracks);
AddMarker(2, 3.0, 10.0, &tracks);
AddMarker(7, 8.0, 35.0, &tracks);
AddMarker(5, 6.0, 25.0, &tracks);
AddMarker(4, 5.0, 20.0, &tracks);
AddMarker(3, 4.0, 15.0, &tracks);
AddMarker(6, 7.0, 30.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
Marker predicted;
predicted.clip = 0;
predicted.track = 0;
predicted.frame = 8;
- PredictMarkerPosition(tracks, &predicted);
+ PredictMarkerPosition(tracks, PredictDirection::AUTO, &predicted);
double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
LG << "Got error: " << error;
EXPECT_LT(error, 0.1);
diff --git a/intern/libmv/libmv/autotrack/quad.h b/intern/libmv/libmv/autotrack/quad.h
index 0c70f9882da..4aeb66f20f7 100644
--- a/intern/libmv/libmv/autotrack/quad.h
+++ b/intern/libmv/libmv/autotrack/quad.h
@@ -27,7 +27,7 @@
namespace mv {
-template<typename T, int D>
+template <typename T, int D>
struct Quad {
// A quad is 4 points; generally in 2D or 3D.
//
@@ -35,7 +35,7 @@ struct Quad {
// |\.
// | \.
// | z (z goes into screen)
- // |
+ // |
// | r0----->r1
// | ^ |
// | | . |
@@ -44,7 +44,7 @@ struct Quad {
// | \.
// | \.
// v normal goes away (right handed).
- // y
+ // y
//
// Each row is one of the corners coordinates; either (x, y) or (x, y, z).
Eigen::Matrix<T, 4, D> coordinates;
diff --git a/intern/libmv/libmv/autotrack/reconstruction.h b/intern/libmv/libmv/autotrack/reconstruction.h
index 732e74063f1..f993b39f79e 100644
--- a/intern/libmv/libmv/autotrack/reconstruction.h
+++ b/intern/libmv/libmv/autotrack/reconstruction.h
@@ -57,17 +57,17 @@ class Reconstruction {
public:
// All methods copy their input reference or take ownership of the pointer.
void AddCameraPose(const CameraPose& pose);
- int AddCameraIntrinsics(CameraIntrinsics* intrinsics);
- int AddPoint(const Point& point);
- int AddModel(Model* model);
+ int AddCameraIntrinsics(CameraIntrinsics* intrinsics);
+ int AddPoint(const Point& point);
+ int AddModel(Model* model);
// Returns the corresponding pose or point or NULL if missing.
- CameraPose* CameraPoseForFrame(int clip, int frame);
+ CameraPose* CameraPoseForFrame(int clip, int frame);
const CameraPose* CameraPoseForFrame(int clip, int frame) const;
- Point* PointForTrack(int track);
+ Point* PointForTrack(int track);
const Point* PointForTrack(int track) const;
- const vector<vector<CameraPose> >& camera_poses() const {
+ const vector<vector<CameraPose>>& camera_poses() const {
return camera_poses_;
}
diff --git a/intern/libmv/libmv/autotrack/region.h b/intern/libmv/libmv/autotrack/region.h
index b35d99eb60d..687a217ab2a 100644
--- a/intern/libmv/libmv/autotrack/region.h
+++ b/intern/libmv/libmv/autotrack/region.h
@@ -46,7 +46,7 @@ struct Region {
Vec2f min;
Vec2f max;
- template<typename T>
+ template <typename T>
void Offset(const T& offset) {
min += offset.template cast<float>();
max += offset.template cast<float>();
diff --git a/intern/libmv/libmv/autotrack/tracks.cc b/intern/libmv/libmv/autotrack/tracks.cc
index 174f264f3f2..8044bb28bb4 100644
--- a/intern/libmv/libmv/autotrack/tracks.cc
+++ b/intern/libmv/libmv/autotrack/tracks.cc
@@ -23,8 +23,8 @@
#include "libmv/autotrack/tracks.h"
#include <algorithm>
-#include <vector>
#include <iterator>
+#include <vector>
#include "libmv/numeric/numeric.h"
@@ -34,12 +34,12 @@ Tracks::Tracks(const Tracks& other) {
markers_ = other.markers_;
}
-Tracks::Tracks(const vector<Marker>& markers) : markers_(markers) {}
+Tracks::Tracks(const vector<Marker>& markers) : markers_(markers) {
+}
bool Tracks::GetMarker(int clip, int frame, int track, Marker* marker) const {
for (int i = 0; i < markers_.size(); ++i) {
- if (markers_[i].clip == clip &&
- markers_[i].frame == frame &&
+ if (markers_[i].clip == clip && markers_[i].frame == frame &&
markers_[i].track == track) {
*marker = markers_[i];
return true;
@@ -60,8 +60,7 @@ void Tracks::GetMarkersForTrackInClip(int clip,
int track,
vector<Marker>* markers) const {
for (int i = 0; i < markers_.size(); ++i) {
- if (clip == markers_[i].clip &&
- track == markers_[i].track) {
+ if (clip == markers_[i].clip && track == markers_[i].track) {
markers->push_back(markers_[i]);
}
}
@@ -71,15 +70,16 @@ void Tracks::GetMarkersInFrame(int clip,
int frame,
vector<Marker>* markers) const {
for (int i = 0; i < markers_.size(); ++i) {
- if (markers_[i].clip == clip &&
- markers_[i].frame == frame) {
+ if (markers_[i].clip == clip && markers_[i].frame == frame) {
markers->push_back(markers_[i]);
}
}
}
-void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1,
- int clip2, int frame2,
+void Tracks::GetMarkersForTracksInBothImages(int clip1,
+ int frame1,
+ int clip2,
+ int frame2,
vector<Marker>* markers) const {
std::vector<int> image1_tracks;
std::vector<int> image2_tracks;
@@ -99,20 +99,19 @@ void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1,
std::sort(image1_tracks.begin(), image1_tracks.end());
std::sort(image2_tracks.begin(), image2_tracks.end());
std::vector<int> intersection;
- std::set_intersection(image1_tracks.begin(), image1_tracks.end(),
- image2_tracks.begin(), image2_tracks.end(),
+ std::set_intersection(image1_tracks.begin(),
+ image1_tracks.end(),
+ image2_tracks.begin(),
+ image2_tracks.end(),
std::back_inserter(intersection));
// Scan through and get the relevant tracks from the two images.
for (int i = 0; i < markers_.size(); ++i) {
// Save markers that are in either frame and are in our candidate set.
- if (((markers_[i].clip == clip1 &&
- markers_[i].frame == frame1) ||
- (markers_[i].clip == clip2 &&
- markers_[i].frame == frame2)) &&
- std::binary_search(intersection.begin(),
- intersection.end(),
- markers_[i].track)) {
+ if (((markers_[i].clip == clip1 && markers_[i].frame == frame1) ||
+ (markers_[i].clip == clip2 && markers_[i].frame == frame2)) &&
+ std::binary_search(
+ intersection.begin(), intersection.end(), markers_[i].track)) {
markers->push_back(markers_[i]);
}
}
@@ -122,8 +121,7 @@ void Tracks::AddMarker(const Marker& marker) {
// TODO(keir): This is quadratic for repeated insertions. Fix this by adding
// a smarter data structure like a set<>.
for (int i = 0; i < markers_.size(); ++i) {
- if (markers_[i].clip == marker.clip &&
- markers_[i].frame == marker.frame &&
+ if (markers_[i].clip == marker.clip && markers_[i].frame == marker.frame &&
markers_[i].track == marker.track) {
markers_[i] = marker;
return;
@@ -139,8 +137,7 @@ void Tracks::SetMarkers(vector<Marker>* markers) {
bool Tracks::RemoveMarker(int clip, int frame, int track) {
int size = markers_.size();
for (int i = 0; i < markers_.size(); ++i) {
- if (markers_[i].clip == clip &&
- markers_[i].frame == frame &&
+ if (markers_[i].clip == clip && markers_[i].frame == frame &&
markers_[i].track == track) {
markers_[i] = markers_[size - 1];
markers_.resize(size - 1);
diff --git a/intern/libmv/libmv/autotrack/tracks.h b/intern/libmv/libmv/autotrack/tracks.h
index 0b7de91d211..dd11a2d6fbd 100644
--- a/intern/libmv/libmv/autotrack/tracks.h
+++ b/intern/libmv/libmv/autotrack/tracks.h
@@ -23,8 +23,8 @@
#ifndef LIBMV_AUTOTRACK_TRACKS_H_
#define LIBMV_AUTOTRACK_TRACKS_H_
-#include "libmv/base/vector.h"
#include "libmv/autotrack/marker.h"
+#include "libmv/base/vector.h"
namespace mv {
@@ -33,8 +33,8 @@ using libmv::vector;
// The Tracks container stores correspondences between frames.
class Tracks {
public:
- Tracks() { }
- Tracks(const Tracks &other);
+ Tracks() {}
+ Tracks(const Tracks& other);
// Create a tracks object with markers already initialized. Copies markers.
explicit Tracks(const vector<Marker>& markers);
@@ -51,8 +51,10 @@ class Tracks {
//
// This is not the same as the union of the markers in frame1 and
// frame2; each marker is for a track that appears in both images.
- void GetMarkersForTracksInBothImages(int clip1, int frame1,
- int clip2, int frame2,
+ void GetMarkersForTracksInBothImages(int clip1,
+ int frame1,
+ int clip2,
+ int frame2,
vector<Marker>* markers) const;
void AddMarker(const Marker& marker);
diff --git a/intern/libmv/libmv/autotrack/tracks_test.cc b/intern/libmv/libmv/autotrack/tracks_test.cc
index 028b4a10913..eeefd3714b0 100644
--- a/intern/libmv/libmv/autotrack/tracks_test.cc
+++ b/intern/libmv/libmv/autotrack/tracks_test.cc
@@ -22,8 +22,8 @@
#include "libmv/autotrack/tracks.h"
-#include "testing/testing.h"
#include "libmv/logging/logging.h"
+#include "testing/testing.h"
namespace mv {
diff --git a/intern/libmv/libmv/base/aligned_malloc.cc b/intern/libmv/libmv/base/aligned_malloc.cc
index 5d3e05e9df9..6e327acf928 100644
--- a/intern/libmv/libmv/base/aligned_malloc.cc
+++ b/intern/libmv/libmv/base/aligned_malloc.cc
@@ -41,11 +41,11 @@
namespace libmv {
-void *aligned_malloc(int size, int alignment) {
+void* aligned_malloc(int size, int alignment) {
#ifdef _WIN32
return _aligned_malloc(size, alignment);
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
- void *result;
+ void* result;
if (posix_memalign(&result, alignment, size)) {
// non-zero means allocation error
@@ -58,7 +58,7 @@ void *aligned_malloc(int size, int alignment) {
#endif
}
-void aligned_free(void *ptr) {
+void aligned_free(void* ptr) {
#ifdef _WIN32
_aligned_free(ptr);
#else
diff --git a/intern/libmv/libmv/base/aligned_malloc.h b/intern/libmv/libmv/base/aligned_malloc.h
index 096ff6e2d7c..25583bb6be4 100644
--- a/intern/libmv/libmv/base/aligned_malloc.h
+++ b/intern/libmv/libmv/base/aligned_malloc.h
@@ -24,10 +24,10 @@
namespace libmv {
// Allocate block of size bytes at least aligned to a given value.
-void *aligned_malloc(int size, int alignment);
+void* aligned_malloc(int size, int alignment);
// Free memory allocated by aligned_malloc.
-void aligned_free(void *ptr);
+void aligned_free(void* ptr);
} // namespace libmv
diff --git a/intern/libmv/libmv/base/id_generator.h b/intern/libmv/libmv/base/id_generator.h
index bf1eafd218e..535c9bd7b38 100644
--- a/intern/libmv/libmv/base/id_generator.h
+++ b/intern/libmv/libmv/base/id_generator.h
@@ -28,6 +28,7 @@ class IdGenerator {
public:
IdGenerator() : next_(0) {}
ID Generate() { return next_++; }
+
private:
ID next_;
};
diff --git a/intern/libmv/libmv/base/map.h b/intern/libmv/libmv/base/map.h
index 88b720f17fe..a91e3561791 100644
--- a/intern/libmv/libmv/base/map.h
+++ b/intern/libmv/libmv/base/map.h
@@ -26,8 +26,8 @@
namespace libmv {
-using std::map;
using std::make_pair;
+using std::map;
} // namespace libmv
diff --git a/intern/libmv/libmv/base/scoped_ptr.h b/intern/libmv/libmv/base/scoped_ptr.h
index b9cd4854213..9bfcfe1d615 100644
--- a/intern/libmv/libmv/base/scoped_ptr.h
+++ b/intern/libmv/libmv/base/scoped_ptr.h
@@ -30,44 +30,44 @@ namespace libmv {
* A handle for a heap-allocated resource that should be freed when it goes out
* of scope. This looks similar to the one found in TR1.
*/
-template<typename T>
+template <typename T>
class scoped_ptr {
public:
- scoped_ptr(T *resource) : resource_(resource) {}
+ scoped_ptr(T* resource) : resource_(resource) {}
~scoped_ptr() { reset(0); }
- T *get() const { return resource_; }
- T *operator->() const { return resource_; }
- T &operator*() const { return *resource_; }
+ T* get() const { return resource_; }
+ T* operator->() const { return resource_; }
+ T& operator*() const { return *resource_; }
- void reset(T *new_resource) {
+ void reset(T* new_resource) {
if (sizeof(T)) {
delete resource_;
}
resource_ = new_resource;
}
- T *release() {
- T *released_resource = resource_;
+ T* release() {
+ T* released_resource = resource_;
resource_ = 0;
return released_resource;
}
private:
// No copying allowed.
- T *resource_;
+ T* resource_;
};
// Same as scoped_ptr but caller must allocate the data
// with new[] and the destructor will free the memory
// using delete[].
-template<typename T>
+template <typename T>
class scoped_array {
public:
- scoped_array(T *array) : array_(array) {}
+ scoped_array(T* array) : array_(array) {}
~scoped_array() { reset(NULL); }
- T *get() const { return array_; }
+ T* get() const { return array_; }
T& operator[](std::ptrdiff_t i) const {
assert(i >= 0);
@@ -75,25 +75,27 @@ class scoped_array {
return array_[i];
}
- void reset(T *new_array) {
+ void reset(T* new_array) {
if (sizeof(T)) {
delete array_;
}
array_ = new_array;
}
- T *release() {
- T *released_array = array_;
+ T* release() {
+ T* released_array = array_;
array_ = NULL;
return released_array;
}
private:
- T *array_;
+ T* array_;
// Forbid comparison of different scoped_array types.
- template <typename T2> bool operator==(scoped_array<T2> const& p2) const;
- template <typename T2> bool operator!=(scoped_array<T2> const& p2) const;
+ template <typename T2>
+ bool operator==(scoped_array<T2> const& p2) const;
+ template <typename T2>
+ bool operator!=(scoped_array<T2> const& p2) const;
// Disallow evil constructors
scoped_array(const scoped_array&);
diff --git a/intern/libmv/libmv/base/scoped_ptr_test.cc b/intern/libmv/libmv/base/scoped_ptr_test.cc
index ce1d56b500a..e86af6d4516 100644
--- a/intern/libmv/libmv/base/scoped_ptr_test.cc
+++ b/intern/libmv/libmv/base/scoped_ptr_test.cc
@@ -25,9 +25,9 @@ namespace libmv {
namespace {
struct FreeMe {
- FreeMe(int *freed) : freed(freed) {}
+ FreeMe(int* freed) : freed(freed) {}
~FreeMe() { (*freed)++; }
- int *freed;
+ int* freed;
};
TEST(ScopedPtr, NullDoesNothing) {
@@ -61,8 +61,8 @@ TEST(ScopedPtr, Reset) {
TEST(ScopedPtr, ReleaseAndGet) {
int frees = 0;
- FreeMe *allocated = new FreeMe(&frees);
- FreeMe *released = NULL;
+ FreeMe* allocated = new FreeMe(&frees);
+ FreeMe* released = NULL;
{
scoped_ptr<FreeMe> scoped(allocated);
EXPECT_EQ(0, frees);
diff --git a/intern/libmv/libmv/base/vector_test.cc b/intern/libmv/libmv/base/vector_test.cc
index f171e3a18b5..d31bee751cd 100644
--- a/intern/libmv/libmv/base/vector_test.cc
+++ b/intern/libmv/libmv/base/vector_test.cc
@@ -19,9 +19,9 @@
// IN THE SOFTWARE.
#include "libmv/base/vector.h"
+#include <algorithm>
#include "libmv/numeric/numeric.h"
#include "testing/testing.h"
-#include <algorithm>
namespace {
using namespace libmv;
@@ -62,7 +62,7 @@ int foo_destruct_calls = 0;
struct Foo {
public:
Foo() : value(5) { foo_construct_calls++; }
- ~Foo() { foo_destruct_calls++; }
+ ~Foo() { foo_destruct_calls++; }
int value;
};
@@ -150,7 +150,7 @@ TEST_F(VectorTest, CopyConstructor) {
a.push_back(3);
vector<int> b(a);
- EXPECT_EQ(a.size(), b.size());
+ EXPECT_EQ(a.size(), b.size());
for (int i = 0; i < a.size(); ++i) {
EXPECT_EQ(a[i], b[i]);
}
@@ -164,7 +164,7 @@ TEST_F(VectorTest, OperatorEquals) {
b = a;
- EXPECT_EQ(a.size(), b.size());
+ EXPECT_EQ(a.size(), b.size());
for (int i = 0; i < a.size(); ++i) {
EXPECT_EQ(a[i], b[i]);
}
diff --git a/intern/libmv/libmv/base/vector_utils.h b/intern/libmv/libmv/base/vector_utils.h
index c71e1bea951..5f69c03d937 100644
--- a/intern/libmv/libmv/base/vector_utils.h
+++ b/intern/libmv/libmv/base/vector_utils.h
@@ -18,14 +18,13 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-
#ifndef LIBMV_BASE_VECTOR_UTILS_H_
#define LIBMV_BASE_VECTOR_UTILS_H_
/// Delete the contents of a container.
template <class Array>
-void DeleteElements(Array *array) {
- for (int i = 0; i < array->size(); ++i) {
+void DeleteElements(Array* array) {
+ for (int i = 0; i < array->size(); ++i) {
delete (*array)[i];
}
array->clear();
diff --git a/intern/libmv/libmv/image/array_nd.cc b/intern/libmv/libmv/image/array_nd.cc
index 469a19aabf1..07feda33e66 100644
--- a/intern/libmv/libmv/image/array_nd.cc
+++ b/intern/libmv/libmv/image/array_nd.cc
@@ -18,18 +18,17 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "libmv/image/image.h"
-#include <iostream>
#include <cmath>
+#include <iostream>
+#include "libmv/image/image.h"
namespace libmv {
-void FloatArrayToScaledByteArray(const Array3Df &float_array,
- Array3Du *byte_array,
- bool automatic_range_detection
- ) {
+void FloatArrayToScaledByteArray(const Array3Df& float_array,
+ Array3Du* byte_array,
+ bool automatic_range_detection) {
byte_array->ResizeLike(float_array);
- float minval = HUGE_VAL;
+ float minval = HUGE_VAL;
float maxval = -HUGE_VAL;
if (automatic_range_detection) {
for (int i = 0; i < float_array.Height(); ++i) {
@@ -54,8 +53,8 @@ void FloatArrayToScaledByteArray(const Array3Df &float_array,
}
}
-void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
- Array3Df *float_array) {
+void ByteArrayToScaledFloatArray(const Array3Du& byte_array,
+ Array3Df* float_array) {
float_array->ResizeLike(byte_array);
for (int i = 0; i < byte_array.Height(); ++i) {
for (int j = 0; j < byte_array.Width(); ++j) {
@@ -66,10 +65,10 @@ void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
}
}
-void SplitChannels(const Array3Df &input,
- Array3Df *channel0,
- Array3Df *channel1,
- Array3Df *channel2) {
+void SplitChannels(const Array3Df& input,
+ Array3Df* channel0,
+ Array3Df* channel1,
+ Array3Df* channel2) {
assert(input.Depth() >= 3);
channel0->Resize(input.Height(), input.Width());
channel1->Resize(input.Height(), input.Width());
@@ -83,7 +82,7 @@ void SplitChannels(const Array3Df &input,
}
}
-void PrintArray(const Array3Df &array) {
+void PrintArray(const Array3Df& array) {
using namespace std;
printf("[\n");
diff --git a/intern/libmv/libmv/image/array_nd.h b/intern/libmv/libmv/image/array_nd.h
index e95e66aa2b3..1a3c39d0461 100644
--- a/intern/libmv/libmv/image/array_nd.h
+++ b/intern/libmv/libmv/image/array_nd.h
@@ -44,13 +44,13 @@ class ArrayND : public BaseArray {
ArrayND() : data_(NULL), own_data_(true) { Resize(Index(0)); }
/// Create an array with the specified shape.
- ArrayND(const Index &shape) : data_(NULL), own_data_(true) { Resize(shape); }
+ ArrayND(const Index& shape) : data_(NULL), own_data_(true) { Resize(shape); }
/// Create an array with the specified shape.
- ArrayND(int *shape) : data_(NULL), own_data_(true) { Resize(shape); }
+ ArrayND(int* shape) : data_(NULL), own_data_(true) { Resize(shape); }
/// Copy constructor.
- ArrayND(const ArrayND<T, N> &b) : data_(NULL), own_data_(true) {
+ ArrayND(const ArrayND<T, N>& b) : data_(NULL), own_data_(true) {
ResizeLike(b);
std::memcpy(Data(), b.Data(), sizeof(T) * Size());
}
@@ -58,7 +58,7 @@ class ArrayND : public BaseArray {
ArrayND(int s0) : data_(NULL), own_data_(true) { Resize(s0); }
ArrayND(int s0, int s1) : data_(NULL), own_data_(true) { Resize(s0, s1); }
ArrayND(int s0, int s1, int s2) : data_(NULL), own_data_(true) {
- Resize(s0, s1, s2);
+ Resize(s0, s1, s2);
}
ArrayND(T* data, int s0, int s1, int s2)
@@ -69,28 +69,24 @@ class ArrayND : public BaseArray {
/// Destructor deletes pixel data.
~ArrayND() {
if (own_data_) {
- delete [] data_;
+ delete[] data_;
}
}
/// Assignation copies pixel data.
- ArrayND &operator=(const ArrayND<T, N> &b) {
+ ArrayND& operator=(const ArrayND<T, N>& b) {
assert(this != &b);
ResizeLike(b);
std::memcpy(Data(), b.Data(), sizeof(T) * Size());
return *this;
}
- const Index &Shapes() const {
- return shape_;
- }
+ const Index& Shapes() const { return shape_; }
- const Index &Strides() const {
- return strides_;
- }
+ const Index& Strides() const { return strides_; }
/// Create an array of shape s.
- void Resize(const Index &new_shape) {
+ void Resize(const Index& new_shape) {
if (data_ != NULL && shape_ == new_shape) {
// Don't bother realloacting if the shapes match.
return;
@@ -101,7 +97,7 @@ class ArrayND : public BaseArray {
strides_(i - 1) = strides_(i) * shape_(i);
}
if (own_data_) {
- delete [] data_;
+ delete[] data_;
data_ = NULL;
if (Size() > 0) {
data_ = new T[Size()];
@@ -109,15 +105,13 @@ class ArrayND : public BaseArray {
}
}
- template<typename D>
- void ResizeLike(const ArrayND<D, N> &other) {
+ template <typename D>
+ void ResizeLike(const ArrayND<D, N>& other) {
Resize(other.Shape());
}
/// Resizes the array to shape s. All data is lost.
- void Resize(const int *new_shape_array) {
- Resize(Index(new_shape_array));
- }
+ void Resize(const int* new_shape_array) { Resize(Index(new_shape_array)); }
/// Resize a 1D array to length s0.
void Resize(int s0) {
@@ -136,9 +130,7 @@ class ArrayND : public BaseArray {
}
// Match Eigen2's API.
- void resize(int rows, int cols) {
- Resize(rows, cols);
- }
+ void resize(int rows, int cols) { Resize(rows, cols); }
/// Resize a 3D array to shape (s0,s1,s2).
void Resize(int s0, int s1, int s2) {
@@ -147,11 +139,11 @@ class ArrayND : public BaseArray {
Resize(shape);
}
- template<typename D>
- void CopyFrom(const ArrayND<D, N> &other) {
+ template <typename D>
+ void CopyFrom(const ArrayND<D, N>& other) {
ResizeLike(other);
- T *data = Data();
- const D *other_data = other.Data();
+ T* data = Data();
+ const D* other_data = other.Data();
for (int i = 0; i < Size(); ++i) {
data[i] = T(other_data[i]);
}
@@ -171,19 +163,13 @@ class ArrayND : public BaseArray {
}
/// Return a tuple containing the length of each axis.
- const Index &Shape() const {
- return shape_;
- }
+ const Index& Shape() const { return shape_; }
/// Return the length of an axis.
- int Shape(int axis) const {
- return shape_(axis);
- }
+ int Shape(int axis) const { return shape_(axis); }
/// Return the distance between neighboring elements along axis.
- int Stride(int axis) const {
- return strides_(axis);
- }
+ int Stride(int axis) const { return strides_(axis); }
/// Return the number of elements of the array.
int Size() const {
@@ -194,18 +180,16 @@ class ArrayND : public BaseArray {
}
/// Return the total amount of memory used by the array.
- int MemorySizeInBytes() const {
- return sizeof(*this) + Size() * sizeof(T);
- }
+ int MemorySizeInBytes() const { return sizeof(*this) + Size() * sizeof(T); }
/// Pointer to the first element of the array.
- T *Data() { return data_; }
+ T* Data() { return data_; }
/// Constant pointer to the first element of the array.
- const T *Data() const { return data_; }
+ const T* Data() const { return data_; }
/// Distance between the first element and the element at position index.
- int Offset(const Index &index) const {
+ int Offset(const Index& index) const {
int offset = 0;
for (int i = 0; i < N; ++i)
offset += index(i) * Stride(i);
@@ -231,25 +215,23 @@ class ArrayND : public BaseArray {
}
/// Return a reference to the element at position index.
- T &operator()(const Index &index) {
+ T& operator()(const Index& index) {
// TODO(pau) Boundary checking in debug mode.
- return *( Data() + Offset(index) );
+ return *(Data() + Offset(index));
}
/// 1D specialization.
- T &operator()(int i0) {
- return *( Data() + Offset(i0) );
- }
+ T& operator()(int i0) { return *(Data() + Offset(i0)); }
/// 2D specialization.
- T &operator()(int i0, int i1) {
+ T& operator()(int i0, int i1) {
assert(0 <= i0 && i0 < Shape(0));
assert(0 <= i1 && i1 < Shape(1));
return *(Data() + Offset(i0, i1));
}
/// 3D specialization.
- T &operator()(int i0, int i1, int i2) {
+ T& operator()(int i0, int i1, int i2) {
assert(0 <= i0 && i0 < Shape(0));
assert(0 <= i1 && i1 < Shape(1));
assert(0 <= i2 && i2 < Shape(2));
@@ -257,29 +239,27 @@ class ArrayND : public BaseArray {
}
/// Return a constant reference to the element at position index.
- const T &operator()(const Index &index) const {
+ const T& operator()(const Index& index) const {
return *(Data() + Offset(index));
}
/// 1D specialization.
- const T &operator()(int i0) const {
- return *(Data() + Offset(i0));
- }
+ const T& operator()(int i0) const { return *(Data() + Offset(i0)); }
/// 2D specialization.
- const T &operator()(int i0, int i1) const {
+ const T& operator()(int i0, int i1) const {
assert(0 <= i0 && i0 < Shape(0));
assert(0 <= i1 && i1 < Shape(1));
return *(Data() + Offset(i0, i1));
}
/// 3D specialization.
- const T &operator()(int i0, int i1, int i2) const {
+ const T& operator()(int i0, int i1, int i2) const {
return *(Data() + Offset(i0, i1, i2));
}
/// True if index is inside array.
- bool Contains(const Index &index) const {
+ bool Contains(const Index& index) const {
for (int i = 0; i < N; ++i)
if (index(i) < 0 || index(i) >= Shape(i))
return false;
@@ -287,26 +267,24 @@ class ArrayND : public BaseArray {
}
/// 1D specialization.
- bool Contains(int i0) const {
- return 0 <= i0 && i0 < Shape(0);
- }
+ bool Contains(int i0) const { return 0 <= i0 && i0 < Shape(0); }
/// 2D specialization.
bool Contains(int i0, int i1) const {
- return 0 <= i0 && i0 < Shape(0)
- && 0 <= i1 && i1 < Shape(1);
+ return 0 <= i0 && i0 < Shape(0) && 0 <= i1 && i1 < Shape(1);
}
/// 3D specialization.
bool Contains(int i0, int i1, int i2) const {
- return 0 <= i0 && i0 < Shape(0)
- && 0 <= i1 && i1 < Shape(1)
- && 0 <= i2 && i2 < Shape(2);
+ return 0 <= i0 && i0 < Shape(0) && 0 <= i1 && i1 < Shape(1) && 0 <= i2 &&
+ i2 < Shape(2);
}
- bool operator==(const ArrayND<T, N> &other) const {
- if (shape_ != other.shape_) return false;
- if (strides_ != other.strides_) return false;
+ bool operator==(const ArrayND<T, N>& other) const {
+ if (shape_ != other.shape_)
+ return false;
+ if (strides_ != other.strides_)
+ return false;
for (int i = 0; i < Size(); ++i) {
if (this->Data()[i] != other.Data()[i])
return false;
@@ -314,11 +292,11 @@ class ArrayND : public BaseArray {
return true;
}
- bool operator!=(const ArrayND<T, N> &other) const {
+ bool operator!=(const ArrayND<T, N>& other) const {
return !(*this == other);
}
- ArrayND<T, N> operator*(const ArrayND<T, N> &other) const {
+ ArrayND<T, N> operator*(const ArrayND<T, N>& other) const {
assert(Shape() = other.Shape());
ArrayND<T, N> res;
res.ResizeLike(*this);
@@ -336,7 +314,7 @@ class ArrayND : public BaseArray {
Index strides_;
/// Pointer to the first element of the array.
- T *data_;
+ T* data_;
/// Flag if this Array either own or reference the data
bool own_data_;
@@ -346,30 +324,20 @@ class ArrayND : public BaseArray {
template <typename T>
class Array3D : public ArrayND<T, 3> {
typedef ArrayND<T, 3> Base;
+
public:
- Array3D()
- : Base() {
- }
- Array3D(int height, int width, int depth = 1)
- : Base(height, width, depth) {
- }
+ Array3D() : Base() {}
+ Array3D(int height, int width, int depth = 1) : Base(height, width, depth) {}
Array3D(T* data, int height, int width, int depth = 1)
- : Base(data, height, width, depth) {
- }
+ : Base(data, height, width, depth) {}
void Resize(int height, int width, int depth = 1) {
Base::Resize(height, width, depth);
}
- int Height() const {
- return Base::Shape(0);
- }
- int Width() const {
- return Base::Shape(1);
- }
- int Depth() const {
- return Base::Shape(2);
- }
+ int Height() const { return Base::Shape(0); }
+ int Width() const { return Base::Shape(1); }
+ int Depth() const { return Base::Shape(2); }
// Match Eigen2's API so that Array3D's and Mat*'s can work together via
// template magic.
@@ -377,15 +345,15 @@ class Array3D : public ArrayND<T, 3> {
int cols() const { return Width(); }
int depth() const { return Depth(); }
- int Get_Step() const { return Width()*Depth(); }
+ int Get_Step() const { return Width() * Depth(); }
/// Enable accessing with 2 indices for grayscale images.
- T &operator()(int i0, int i1, int i2 = 0) {
+ T& operator()(int i0, int i1, int i2 = 0) {
assert(0 <= i0 && i0 < Height());
assert(0 <= i1 && i1 < Width());
return Base::operator()(i0, i1, i2);
}
- const T &operator()(int i0, int i1, int i2 = 0) const {
+ const T& operator()(int i0, int i1, int i2 = 0) const {
assert(0 <= i0 && i0 < Height());
assert(0 <= i1 && i1 < Width());
return Base::operator()(i0, i1, i2);
@@ -398,31 +366,29 @@ typedef Array3D<int> Array3Di;
typedef Array3D<float> Array3Df;
typedef Array3D<short> Array3Ds;
-void SplitChannels(const Array3Df &input,
- Array3Df *channel0,
- Array3Df *channel1,
- Array3Df *channel2);
+void SplitChannels(const Array3Df& input,
+ Array3Df* channel0,
+ Array3Df* channel1,
+ Array3Df* channel2);
-void PrintArray(const Array3Df &array);
+void PrintArray(const Array3Df& array);
/** Convert a float array into a byte array by scaling values by 255* (max-min).
- * where max and min are automatically detected
+ * where max and min are automatically detected
* (if automatic_range_detection = true)
* \note and TODO this automatic detection only works when the image contains
* at least one pixel of both bounds.
**/
-void FloatArrayToScaledByteArray(const Array3Df &float_array,
- Array3Du *byte_array,
+void FloatArrayToScaledByteArray(const Array3Df& float_array,
+ Array3Du* byte_array,
bool automatic_range_detection = false);
//! Convert a byte array into a float array by dividing values by 255.
-void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
- Array3Df *float_array);
+void ByteArrayToScaledFloatArray(const Array3Du& byte_array,
+ Array3Df* float_array);
template <typename AArrayType, typename BArrayType, typename CArrayType>
-void MultiplyElements(const AArrayType &a,
- const BArrayType &b,
- CArrayType *c) {
+void MultiplyElements(const AArrayType& a, const BArrayType& b, CArrayType* c) {
// This function does an element-wise multiply between
// the two Arrays A and B, and stores the result in C.
// A and B must have the same dimensions.
@@ -435,7 +401,7 @@ void MultiplyElements(const AArrayType &a,
// The index starts at the maximum value for each dimension
const typename CArrayType::Index& cShape = c->Shape();
- for ( int i = 0; i < CArrayType::Index::SIZE; ++i )
+ for (int i = 0; i < CArrayType::Index::SIZE; ++i)
index(i) = cShape(i) - 1;
// After each multiplication, the highest-dimensional index is reduced.
@@ -443,12 +409,12 @@ void MultiplyElements(const AArrayType &a,
// and decrements the index of the next lower dimension.
// This ripple-action continues until the entire new array has been
// calculated, indicated by dimension zero having a negative index.
- while ( index(0) >= 0 ) {
+ while (index(0) >= 0) {
(*c)(index) = a(index) * b(index);
int dimension = CArrayType::Index::SIZE - 1;
index(dimension) = index(dimension) - 1;
- while ( dimension > 0 && index(dimension) < 0 ) {
+ while (dimension > 0 && index(dimension) < 0) {
index(dimension) = cShape(dimension) - 1;
index(dimension - 1) = index(dimension - 1) - 1;
--dimension;
@@ -457,9 +423,9 @@ void MultiplyElements(const AArrayType &a,
}
template <typename TA, typename TB, typename TC>
-void MultiplyElements(const ArrayND<TA, 3> &a,
- const ArrayND<TB, 3> &b,
- ArrayND<TC, 3> *c) {
+void MultiplyElements(const ArrayND<TA, 3>& a,
+ const ArrayND<TB, 3>& b,
+ ArrayND<TC, 3>* c) {
// Specialization for N==3
c->ResizeLike(a);
assert(a.Shape(0) == b.Shape(0));
@@ -475,9 +441,9 @@ void MultiplyElements(const ArrayND<TA, 3> &a,
}
template <typename TA, typename TB, typename TC>
-void MultiplyElements(const Array3D<TA> &a,
- const Array3D<TB> &b,
- Array3D<TC> *c) {
+void MultiplyElements(const Array3D<TA>& a,
+ const Array3D<TB>& b,
+ Array3D<TC>* c) {
// Specialization for N==3
c->ResizeLike(a);
assert(a.Shape(0) == b.Shape(0));
diff --git a/intern/libmv/libmv/image/array_nd_test.cc b/intern/libmv/libmv/image/array_nd_test.cc
index dc7cfacf90d..67838d34051 100644
--- a/intern/libmv/libmv/image/array_nd_test.cc
+++ b/intern/libmv/libmv/image/array_nd_test.cc
@@ -21,9 +21,9 @@
#include "libmv/image/array_nd.h"
#include "testing/testing.h"
-using libmv::ArrayND;
using libmv::Array3D;
using libmv::Array3Df;
+using libmv::ArrayND;
namespace {
@@ -100,7 +100,7 @@ TEST(ArrayND, Size) {
int l[] = {0, 1, 2};
ArrayND<int, 3>::Index last(l);
- EXPECT_EQ(a.Size(), a.Offset(last)+1);
+ EXPECT_EQ(a.Size(), a.Offset(last) + 1);
EXPECT_TRUE(a.Contains(last));
EXPECT_FALSE(a.Contains(shape));
}
@@ -120,8 +120,8 @@ TEST(ArrayND, Parenthesis) {
int s[] = {3, 3};
ArrayND<int, 2> a(s);
- *(a.Data()+0) = 0;
- *(a.Data()+5) = 5;
+ *(a.Data() + 0) = 0;
+ *(a.Data() + 5) = 5;
int i1[] = {0, 0};
EXPECT_EQ(0, a(Index(i1)));
@@ -210,7 +210,7 @@ TEST(ArrayND, MultiplyElements) {
b(1, 1, 0) = 3;
ArrayND<int, 3> c;
MultiplyElements(a, b, &c);
- EXPECT_FLOAT_EQ(6, c(0, 0, 0));
+ EXPECT_FLOAT_EQ(6, c(0, 0, 0));
EXPECT_FLOAT_EQ(10, c(0, 1, 0));
EXPECT_FLOAT_EQ(12, c(1, 0, 0));
EXPECT_FLOAT_EQ(12, c(1, 1, 0));
diff --git a/intern/libmv/libmv/image/convolve.cc b/intern/libmv/libmv/image/convolve.cc
index 464043581d2..478e320377d 100644
--- a/intern/libmv/libmv/image/convolve.cc
+++ b/intern/libmv/libmv/image/convolve.cc
@@ -29,7 +29,7 @@ namespace libmv {
// Compute a Gaussian kernel and derivative, such that you can take the
// derivative of an image by convolving with the kernel horizontally then the
// derivative vertically to get (eg) the y derivative.
-void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) {
+void ComputeGaussianKernel(double sigma, Vec* kernel, Vec* derivative) {
assert(sigma >= 0.0);
// 0.004 implies a 3 pixel kernel with 1 pixel sigma.
@@ -37,7 +37,7 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) {
// Calculate the kernel size based on sigma such that it is odd.
float precisehalfwidth = GaussianInversePositive(truncation_factor, sigma);
- int width = lround(2*precisehalfwidth);
+ int width = lround(2 * precisehalfwidth);
if (width % 2 == 0) {
width++;
}
@@ -47,7 +47,7 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) {
kernel->setZero();
derivative->setZero();
int halfwidth = width / 2;
- for (int i = -halfwidth; i <= halfwidth; ++i) {
+ for (int i = -halfwidth; i <= halfwidth; ++i) {
(*kernel)(i + halfwidth) = Gaussian(i, sigma);
(*derivative)(i + halfwidth) = GaussianDerivative(i, sigma);
}
@@ -57,16 +57,21 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) {
// Normalize the derivative differently. See
// www.cs.duke.edu/courses/spring03/cps296.1/handouts/Image%20Processing.pdf
double factor = 0.;
- for (int i = -halfwidth; i <= halfwidth; ++i) {
- factor -= i*(*derivative)(i+halfwidth);
+ for (int i = -halfwidth; i <= halfwidth; ++i) {
+ factor -= i * (*derivative)(i + halfwidth);
}
*derivative /= factor;
}
template <int size, bool vertical>
-void FastConvolve(const Vec &kernel, int width, int height,
- const float* src, int src_stride, int src_line_stride,
- float* dst, int dst_stride) {
+void FastConvolve(const Vec& kernel,
+ int width,
+ int height,
+ const float* src,
+ int src_stride,
+ int src_line_stride,
+ float* dst,
+ int dst_stride) {
double coefficients[2 * size + 1];
for (int k = 0; k < 2 * size + 1; ++k) {
coefficients[k] = kernel(2 * size - k);
@@ -93,14 +98,14 @@ void FastConvolve(const Vec &kernel, int width, int height,
}
}
-template<bool vertical>
-void Convolve(const Array3Df &in,
- const Vec &kernel,
- Array3Df *out_pointer,
+template <bool vertical>
+void Convolve(const Array3Df& in,
+ const Vec& kernel,
+ Array3Df* out_pointer,
int plane) {
int width = in.Width();
int height = in.Height();
- Array3Df &out = *out_pointer;
+ Array3Df& out = *out_pointer;
if (plane == -1) {
out.ResizeLike(in);
plane = 0;
@@ -119,61 +124,62 @@ void Convolve(const Array3Df &in,
// fast path.
int half_width = kernel.size() / 2;
switch (half_width) {
-#define static_convolution(size) case size: \
- FastConvolve<size, vertical>(kernel, width, height, src, src_stride, \
- src_line_stride, dst, dst_stride); break;
- static_convolution(1)
- static_convolution(2)
- static_convolution(3)
- static_convolution(4)
- static_convolution(5)
- static_convolution(6)
- static_convolution(7)
+#define static_convolution(size) \
+ case size: \
+ FastConvolve<size, vertical>(kernel, \
+ width, \
+ height, \
+ src, \
+ src_stride, \
+ src_line_stride, \
+ dst, \
+ dst_stride); \
+ break;
+ static_convolution(1) static_convolution(2) static_convolution(3)
+ static_convolution(4) static_convolution(5) static_convolution(6)
+ static_convolution(7)
#undef static_convolution
- default:
- int dynamic_size = kernel.size() / 2;
- for (int y = 0; y < height; ++y) {
- for (int x = 0; x < width; ++x) {
- double sum = 0;
- // Slow path: this loop cannot be unrolled.
- for (int k = -dynamic_size; k <= dynamic_size; ++k) {
- if (vertical) {
- if (y + k >= 0 && y + k < height) {
- sum += src[k * src_line_stride] *
- kernel(2 * dynamic_size - (k + dynamic_size));
- }
- } else {
- if (x + k >= 0 && x + k < width) {
- sum += src[k * src_stride] *
- kernel(2 * dynamic_size - (k + dynamic_size));
- }
+ default : int dynamic_size = kernel.size() / 2;
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ double sum = 0;
+ // Slow path: this loop cannot be unrolled.
+ for (int k = -dynamic_size; k <= dynamic_size; ++k) {
+ if (vertical) {
+ if (y + k >= 0 && y + k < height) {
+ sum += src[k * src_line_stride] *
+ kernel(2 * dynamic_size - (k + dynamic_size));
+ }
+ } else {
+ if (x + k >= 0 && x + k < width) {
+ sum += src[k * src_stride] *
+ kernel(2 * dynamic_size - (k + dynamic_size));
}
}
- dst[0] = static_cast<float>(sum);
- src += src_stride;
- dst += dst_stride;
}
+ dst[0] = static_cast<float>(sum);
+ src += src_stride;
+ dst += dst_stride;
}
+ }
}
}
-void ConvolveHorizontal(const Array3Df &in,
- const Vec &kernel,
- Array3Df *out_pointer,
+void ConvolveHorizontal(const Array3Df& in,
+ const Vec& kernel,
+ Array3Df* out_pointer,
int plane) {
Convolve<false>(in, kernel, out_pointer, plane);
}
-void ConvolveVertical(const Array3Df &in,
- const Vec &kernel,
- Array3Df *out_pointer,
+void ConvolveVertical(const Array3Df& in,
+ const Vec& kernel,
+ Array3Df* out_pointer,
int plane) {
Convolve<true>(in, kernel, out_pointer, plane);
}
-void ConvolveGaussian(const Array3Df &in,
- double sigma,
- Array3Df *out_pointer) {
+void ConvolveGaussian(const Array3Df& in, double sigma, Array3Df* out_pointer) {
Vec kernel, derivative;
ComputeGaussianKernel(sigma, &kernel, &derivative);
@@ -182,10 +188,10 @@ void ConvolveGaussian(const Array3Df &in,
ConvolveHorizontal(tmp, kernel, out_pointer);
}
-void ImageDerivatives(const Array3Df &in,
+void ImageDerivatives(const Array3Df& in,
double sigma,
- Array3Df *gradient_x,
- Array3Df *gradient_y) {
+ Array3Df* gradient_x,
+ Array3Df* gradient_y) {
Vec kernel, derivative;
ComputeGaussianKernel(sigma, &kernel, &derivative);
Array3Df tmp;
@@ -199,11 +205,11 @@ void ImageDerivatives(const Array3Df &in,
ConvolveVertical(tmp, derivative, gradient_y);
}
-void BlurredImageAndDerivatives(const Array3Df &in,
+void BlurredImageAndDerivatives(const Array3Df& in,
double sigma,
- Array3Df *blurred_image,
- Array3Df *gradient_x,
- Array3Df *gradient_y) {
+ Array3Df* blurred_image,
+ Array3Df* gradient_x,
+ Array3Df* gradient_y) {
Vec kernel, derivative;
ComputeGaussianKernel(sigma, &kernel, &derivative);
Array3Df tmp;
@@ -224,9 +230,9 @@ void BlurredImageAndDerivatives(const Array3Df &in,
// image, and store the results in three channels. Since the blurred value and
// gradients are closer in memory, this leads to better performance if all
// three values are needed at the same time.
-void BlurredImageAndDerivativesChannels(const Array3Df &in,
+void BlurredImageAndDerivativesChannels(const Array3Df& in,
double sigma,
- Array3Df *blurred_and_gradxy) {
+ Array3Df* blurred_and_gradxy) {
assert(in.Depth() == 1);
Vec kernel, derivative;
@@ -246,10 +252,10 @@ void BlurredImageAndDerivativesChannels(const Array3Df &in,
ConvolveVertical(tmp, derivative, blurred_and_gradxy, 2);
}
-void BoxFilterHorizontal(const Array3Df &in,
+void BoxFilterHorizontal(const Array3Df& in,
int window_size,
- Array3Df *out_pointer) {
- Array3Df &out = *out_pointer;
+ Array3Df* out_pointer) {
+ Array3Df& out = *out_pointer;
out.ResizeLike(in);
int half_width = (window_size - 1) / 2;
@@ -266,7 +272,7 @@ void BoxFilterHorizontal(const Array3Df &in,
out(i, j, k) = sum;
}
// Fill interior.
- for (int j = half_width + 1; j < in.Width()-half_width; ++j) {
+ for (int j = half_width + 1; j < in.Width() - half_width; ++j) {
sum -= in(i, j - half_width - 1, k);
sum += in(i, j + half_width, k);
out(i, j, k) = sum;
@@ -280,10 +286,10 @@ void BoxFilterHorizontal(const Array3Df &in,
}
}
-void BoxFilterVertical(const Array3Df &in,
+void BoxFilterVertical(const Array3Df& in,
int window_size,
- Array3Df *out_pointer) {
- Array3Df &out = *out_pointer;
+ Array3Df* out_pointer) {
+ Array3Df& out = *out_pointer;
out.ResizeLike(in);
int half_width = (window_size - 1) / 2;
@@ -300,7 +306,7 @@ void BoxFilterVertical(const Array3Df &in,
out(i, j, k) = sum;
}
// Fill interior.
- for (int i = half_width + 1; i < in.Height()-half_width; ++i) {
+ for (int i = half_width + 1; i < in.Height() - half_width; ++i) {
sum -= in(i - half_width - 1, j, k);
sum += in(i + half_width, j, k);
out(i, j, k) = sum;
@@ -314,9 +320,7 @@ void BoxFilterVertical(const Array3Df &in,
}
}
-void BoxFilter(const Array3Df &in,
- int box_width,
- Array3Df *out) {
+void BoxFilter(const Array3Df& in, int box_width, Array3Df* out) {
Array3Df tmp;
BoxFilterHorizontal(in, box_width, &tmp);
BoxFilterVertical(tmp, box_width, out);
@@ -327,17 +331,17 @@ void LaplaceFilter(unsigned char* src,
int width,
int height,
int strength) {
- for (int y = 1; y < height-1; y++)
- for (int x = 1; x < width-1; x++) {
- const unsigned char* s = &src[y*width+x];
- int l = 128 +
- s[-width-1] + s[-width] + s[-width+1] +
- s[1] - 8*s[0] + s[1] +
- s[ width-1] + s[ width] + s[ width+1];
- int d = ((256-strength)*s[0] + strength*l) / 256;
- if (d < 0) d=0;
- if (d > 255) d=255;
- dst[y*width+x] = d;
+ for (int y = 1; y < height - 1; y++)
+ for (int x = 1; x < width - 1; x++) {
+ const unsigned char* s = &src[y * width + x];
+ int l = 128 + s[-width - 1] + s[-width] + s[-width + 1] + s[1] -
+ 8 * s[0] + s[1] + s[width - 1] + s[width] + s[width + 1];
+ int d = ((256 - strength) * s[0] + strength * l) / 256;
+ if (d < 0)
+ d = 0;
+ if (d > 255)
+ d = 255;
+ dst[y * width + x] = d;
}
}
diff --git a/intern/libmv/libmv/image/convolve.h b/intern/libmv/libmv/image/convolve.h
index d3b6da9794b..3794550eb73 100644
--- a/intern/libmv/libmv/image/convolve.h
+++ b/intern/libmv/libmv/image/convolve.h
@@ -30,70 +30,71 @@ namespace libmv {
// Zero mean Gaussian.
inline double Gaussian(double x, double sigma) {
- return 1/sqrt(2*M_PI*sigma*sigma) * exp(-(x*x/2/sigma/sigma));
+ return 1 / sqrt(2 * M_PI * sigma * sigma) * exp(-(x * x / 2 / sigma / sigma));
}
// 2D gaussian (zero mean)
// (9) in http://mathworld.wolfram.com/GaussianFunction.html
inline double Gaussian2D(double x, double y, double sigma) {
- return 1.0/(2.0*M_PI*sigma*sigma) * exp( -(x*x+y*y)/(2.0*sigma*sigma));
+ return 1.0 / (2.0 * M_PI * sigma * sigma) *
+ exp(-(x * x + y * y) / (2.0 * sigma * sigma));
}
inline double GaussianDerivative(double x, double sigma) {
return -x / sigma / sigma * Gaussian(x, sigma);
}
// Solve the inverse of the Gaussian for positive x.
inline double GaussianInversePositive(double y, double sigma) {
- return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2*M_PI)));
+ return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2 * M_PI)));
}
-void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative);
-void ConvolveHorizontal(const FloatImage &in,
- const Vec &kernel,
- FloatImage *out_pointer,
+void ComputeGaussianKernel(double sigma, Vec* kernel, Vec* derivative);
+void ConvolveHorizontal(const FloatImage& in,
+ const Vec& kernel,
+ FloatImage* out_pointer,
int plane = -1);
-void ConvolveVertical(const FloatImage &in,
- const Vec &kernel,
- FloatImage *out_pointer,
+void ConvolveVertical(const FloatImage& in,
+ const Vec& kernel,
+ FloatImage* out_pointer,
int plane = -1);
-void ConvolveGaussian(const FloatImage &in,
+void ConvolveGaussian(const FloatImage& in,
double sigma,
- FloatImage *out_pointer);
+ FloatImage* out_pointer);
-void ImageDerivatives(const FloatImage &in,
+void ImageDerivatives(const FloatImage& in,
double sigma,
- FloatImage *gradient_x,
- FloatImage *gradient_y);
+ FloatImage* gradient_x,
+ FloatImage* gradient_y);
-void BlurredImageAndDerivatives(const FloatImage &in,
+void BlurredImageAndDerivatives(const FloatImage& in,
double sigma,
- FloatImage *blurred_image,
- FloatImage *gradient_x,
- FloatImage *gradient_y);
+ FloatImage* blurred_image,
+ FloatImage* gradient_x,
+ FloatImage* gradient_y);
// Blur and take the gradients of an image, storing the results inside the
// three channels of blurred_and_gradxy.
-void BlurredImageAndDerivativesChannels(const FloatImage &in,
+void BlurredImageAndDerivativesChannels(const FloatImage& in,
double sigma,
- FloatImage *blurred_and_gradxy);
+ FloatImage* blurred_and_gradxy);
-void BoxFilterHorizontal(const FloatImage &in,
+void BoxFilterHorizontal(const FloatImage& in,
int window_size,
- FloatImage *out_pointer);
+ FloatImage* out_pointer);
-void BoxFilterVertical(const FloatImage &in,
+void BoxFilterVertical(const FloatImage& in,
int window_size,
- FloatImage *out_pointer);
+ FloatImage* out_pointer);
-void BoxFilter(const FloatImage &in,
- int box_width,
- FloatImage *out);
+void BoxFilter(const FloatImage& in, int box_width, FloatImage* out);
/*!
Convolve \a src into \a dst with the discrete laplacian operator.
\a src and \a dst should be \a width x \a height images.
- \a strength is an interpolation coefficient (0-256) between original image and the laplacian.
+ \a strength is an interpolation coefficient (0-256) between original image
+ and the laplacian.
- \note Make sure the search region is filtered with the same strength as the pattern.
+ \note Make sure the search region is filtered with the same strength as the
+ pattern.
*/
void LaplaceFilter(unsigned char* src,
unsigned char* dst,
@@ -104,4 +105,3 @@ void LaplaceFilter(unsigned char* src,
} // namespace libmv
#endif // LIBMV_IMAGE_CONVOLVE_H_
-
diff --git a/intern/libmv/libmv/image/convolve_test.cc b/intern/libmv/libmv/image/convolve_test.cc
index 0cdef8e1e72..1ad4cb9a40e 100644
--- a/intern/libmv/libmv/image/convolve_test.cc
+++ b/intern/libmv/libmv/image/convolve_test.cc
@@ -85,26 +85,26 @@ TEST(Convolve, BlurredImageAndDerivativesChannelsHorizontalSlope) {
FloatImage image(10, 10), blurred_and_derivatives;
for (int j = 0; j < 10; ++j) {
for (int i = 0; i < 10; ++i) {
- image(j, i) = 2*i;
+ image(j, i) = 2 * i;
}
}
BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives);
EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7);
- EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7);
- EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7);
+ EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7);
+ EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7);
}
TEST(Convolve, BlurredImageAndDerivativesChannelsVerticalSlope) {
FloatImage image(10, 10), blurred_and_derivatives;
for (int j = 0; j < 10; ++j) {
for (int i = 0; i < 10; ++i) {
- image(j, i) = 2*j;
+ image(j, i) = 2 * j;
}
}
BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives);
EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7);
- EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7);
- EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7);
+ EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7);
+ EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7);
}
} // namespace
diff --git a/intern/libmv/libmv/image/correlation.h b/intern/libmv/libmv/image/correlation.h
index c354f7e891e..25123efe8d0 100644
--- a/intern/libmv/libmv/image/correlation.h
+++ b/intern/libmv/libmv/image/correlation.h
@@ -21,14 +21,14 @@
#ifndef LIBMV_IMAGE_CORRELATION_H
#define LIBMV_IMAGE_CORRELATION_H
-#include "libmv/logging/logging.h"
#include "libmv/image/image.h"
+#include "libmv/logging/logging.h"
namespace libmv {
inline double PearsonProductMomentCorrelation(
- const FloatImage &image_and_gradient1_sampled,
- const FloatImage &image_and_gradient2_sampled) {
+ const FloatImage& image_and_gradient1_sampled,
+ const FloatImage& image_and_gradient2_sampled) {
assert(image_and_gradient1_sampled.Width() ==
image_and_gradient2_sampled.Width());
assert(image_and_gradient1_sampled.Height() ==
@@ -63,9 +63,8 @@ inline double PearsonProductMomentCorrelation(
double covariance_xy = sXY - sX * sY;
double correlation = covariance_xy / sqrt(var_x * var_y);
- LG << "Covariance xy: " << covariance_xy
- << ", var 1: " << var_x << ", var 2: " << var_y
- << ", correlation: " << correlation;
+ LG << "Covariance xy: " << covariance_xy << ", var 1: " << var_x
+ << ", var 2: " << var_y << ", correlation: " << correlation;
return correlation;
}
diff --git a/intern/libmv/libmv/image/image.h b/intern/libmv/libmv/image/image.h
index e0f200a4c93..40d6aa6f70a 100644
--- a/intern/libmv/libmv/image/image.h
+++ b/intern/libmv/libmv/image/image.h
@@ -39,14 +39,11 @@ typedef Array3Ds ShortImage;
// is the best solution after all.
class Image {
public:
-
// Create an image from an array. The image takes ownership of the array.
- Image(Array3Du *array) : array_type_(BYTE), array_(array) {}
- Image(Array3Df *array) : array_type_(FLOAT), array_(array) {}
+ Image(Array3Du* array) : array_type_(BYTE), array_(array) {}
+ Image(Array3Df* array) : array_type_(FLOAT), array_(array) {}
- Image(const Image &img): array_type_(NONE), array_(NULL) {
- *this = img;
- }
+ Image(const Image& img) : array_type_(NONE), array_(NULL) { *this = img; }
// Underlying data type.
enum DataType {
@@ -62,20 +59,18 @@ class Image {
int size;
switch (array_type_) {
case BYTE:
- size = reinterpret_cast<Array3Du *>(array_)->MemorySizeInBytes();
- break;
+ size = reinterpret_cast<Array3Du*>(array_)->MemorySizeInBytes();
+ break;
case FLOAT:
- size = reinterpret_cast<Array3Df *>(array_)->MemorySizeInBytes();
- break;
+ size = reinterpret_cast<Array3Df*>(array_)->MemorySizeInBytes();
+ break;
case INT:
- size = reinterpret_cast<Array3Di *>(array_)->MemorySizeInBytes();
- break;
+ size = reinterpret_cast<Array3Di*>(array_)->MemorySizeInBytes();
+ break;
case SHORT:
- size = reinterpret_cast<Array3Ds *>(array_)->MemorySizeInBytes();
- break;
- default :
- size = 0;
- assert(0);
+ size = reinterpret_cast<Array3Ds*>(array_)->MemorySizeInBytes();
+ break;
+ default: size = 0; assert(0);
}
size += sizeof(*this);
return size;
@@ -83,71 +78,57 @@ class Image {
~Image() {
switch (array_type_) {
- case BYTE:
- delete reinterpret_cast<Array3Du *>(array_);
-
- break;
- case FLOAT:
- delete reinterpret_cast<Array3Df *>(array_);
-
- break;
- case INT:
- delete reinterpret_cast<Array3Di *>(array_);
-
- break;
- case SHORT:
- delete reinterpret_cast<Array3Ds *>(array_);
-
- break;
- default:
- assert(0);
- }
+ case BYTE: delete reinterpret_cast<Array3Du*>(array_); break;
+ case FLOAT: delete reinterpret_cast<Array3Df*>(array_); break;
+ case INT: delete reinterpret_cast<Array3Di*>(array_); break;
+ case SHORT: delete reinterpret_cast<Array3Ds*>(array_); break;
+ default: assert(0);
+ }
}
- Image& operator= (const Image& f) {
+ Image& operator=(const Image& f) {
if (this != &f) {
array_type_ = f.array_type_;
switch (array_type_) {
case BYTE:
- delete reinterpret_cast<Array3Du *>(array_);
- array_ = new Array3Du(*(Array3Du *)f.array_);
- break;
+ delete reinterpret_cast<Array3Du*>(array_);
+ array_ = new Array3Du(*(Array3Du*)f.array_);
+ break;
case FLOAT:
- delete reinterpret_cast<Array3Df *>(array_);
- array_ = new Array3Df(*(Array3Df *)f.array_);
- break;
+ delete reinterpret_cast<Array3Df*>(array_);
+ array_ = new Array3Df(*(Array3Df*)f.array_);
+ break;
case INT:
- delete reinterpret_cast<Array3Di *>(array_);
- array_ = new Array3Di(*(Array3Di *)f.array_);
- break;
+ delete reinterpret_cast<Array3Di*>(array_);
+ array_ = new Array3Di(*(Array3Di*)f.array_);
+ break;
case SHORT:
- delete reinterpret_cast<Array3Ds *>(array_);
- array_ = new Array3Ds(*(Array3Ds *)f.array_);
- break;
- default:
- assert(0);
+ delete reinterpret_cast<Array3Ds*>(array_);
+ array_ = new Array3Ds(*(Array3Ds*)f.array_);
+ break;
+ default: assert(0);
}
}
return *this;
}
- Array3Du *AsArray3Du() const {
+ Array3Du* AsArray3Du() const {
if (array_type_ == BYTE) {
- return reinterpret_cast<Array3Du *>(array_);
+ return reinterpret_cast<Array3Du*>(array_);
}
return NULL;
}
- Array3Df *AsArray3Df() const {
+ Array3Df* AsArray3Df() const {
if (array_type_ == FLOAT) {
- return reinterpret_cast<Array3Df *>(array_);
+ return reinterpret_cast<Array3Df*>(array_);
}
return NULL;
}
private:
DataType array_type_;
- BaseArray *array_;
+ BaseArray* array_;
};
} // namespace libmv
diff --git a/intern/libmv/libmv/image/image_converter.h b/intern/libmv/libmv/image/image_converter.h
index b3a3fa2bf8c..41d53be6722 100644
--- a/intern/libmv/libmv/image/image_converter.h
+++ b/intern/libmv/libmv/image/image_converter.h
@@ -28,7 +28,7 @@ namespace libmv {
// The factor comes from http://www.easyrgb.com/
// RGB to XYZ : Y is the luminance channel
// var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
-template<typename T>
+template <typename T>
inline T RGB2GRAY(const T r, const T g, const T b) {
return static_cast<T>(r * 0.2126 + g * 0.7152 + b * 0.0722);
}
@@ -42,8 +42,8 @@ inline unsigned char RGB2GRAY<unsigned char>(const unsigned char r,
return (unsigned char)(r * 0.2126 + g * 0.7152 + b * 0.0722 +0.5);
}*/
-template<class ImageIn, class ImageOut>
-void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) {
+template <class ImageIn, class ImageOut>
+void Rgb2Gray(const ImageIn& imaIn, ImageOut* imaOut) {
// It is all fine to cnvert RGBA image here as well,
// all the additional channels will be nicely ignored.
assert(imaIn.Depth() >= 3);
@@ -52,21 +52,22 @@ void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) {
// Convert each RGB pixel into Gray value (luminance)
for (int j = 0; j < imaIn.Height(); ++j) {
- for (int i = 0; i < imaIn.Width(); ++i) {
- (*imaOut)(j, i) = RGB2GRAY(imaIn(j, i, 0) , imaIn(j, i, 1), imaIn(j, i, 2));
+ for (int i = 0; i < imaIn.Width(); ++i) {
+ (*imaOut)(j, i) =
+ RGB2GRAY(imaIn(j, i, 0), imaIn(j, i, 1), imaIn(j, i, 2));
}
}
}
// Convert given float image to an unsigned char array of pixels.
-template<class Image>
-unsigned char *FloatImageToUCharArray(const Image &image) {
- unsigned char *buffer =
+template <class Image>
+unsigned char* FloatImageToUCharArray(const Image& image) {
+ unsigned char* buffer =
new unsigned char[image.Width() * image.Height() * image.Depth()];
for (int y = 0; y < image.Height(); y++) {
- for (int x = 0; x < image.Width(); x++) {
- for (int d = 0; d < image.Depth(); d++) {
+ for (int x = 0; x < image.Width(); x++) {
+ for (int d = 0; d < image.Depth(); d++) {
int index = (y * image.Width() + x) * image.Depth() + d;
buffer[index] = 255.0 * image(y, x, d);
}
diff --git a/intern/libmv/libmv/image/image_drawing.h b/intern/libmv/libmv/image/image_drawing.h
index f50e48b75a3..dd6a94dd7d4 100644
--- a/intern/libmv/libmv/image/image_drawing.h
+++ b/intern/libmv/libmv/image/image_drawing.h
@@ -34,9 +34,9 @@ namespace libmv {
/// Put the pixel in the image to the given color only if the point (xc,yc)
/// is inside the image.
template <class Image, class Color>
-inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) {
+inline void safePutPixel(int yc, int xc, const Color& col, Image* pim) {
if (!pim)
- return;
+ return;
if (pim->Contains(yc, xc)) {
(*pim)(yc, xc) = col;
}
@@ -45,9 +45,9 @@ inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) {
/// is inside the image. This function support multi-channel color
/// \note The color pointer col must have size as the image depth
template <class Image, class Color>
-inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) {
+inline void safePutPixel(int yc, int xc, const Color* col, Image* pim) {
if (!pim)
- return;
+ return;
if (pim->Contains(yc, xc)) {
for (int i = 0; i < pim->Depth(); ++i)
(*pim)(yc, xc, i) = *(col + i);
@@ -59,19 +59,23 @@ inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) {
// Add the rotation of the ellipse.
// As the algo. use symmetry we must use 4 rotations.
template <class Image, class Color>
-void DrawEllipse(int xc, int yc, int radiusA, int radiusB,
- const Color &col, Image *pim, double angle = 0.0) {
+void DrawEllipse(int xc,
+ int yc,
+ int radiusA,
+ int radiusB,
+ const Color& col,
+ Image* pim,
+ double angle = 0.0) {
int a = radiusA;
int b = radiusB;
// Counter Clockwise rotation matrix.
- double matXY[4] = { cos(angle), sin(angle),
- -sin(angle), cos(angle)};
+ double matXY[4] = {cos(angle), sin(angle), -sin(angle), cos(angle)};
int x, y;
double d1, d2;
x = 0;
y = b;
- d1 = b*b - a*a*b + a*a/4;
+ d1 = b * b - a * a * b + a * a / 4;
float rotX = (matXY[0] * x + matXY[1] * y);
float rotY = (matXY[2] * x + matXY[3] * y);
@@ -86,12 +90,12 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB,
rotY = (-matXY[2] * x + matXY[3] * y);
safePutPixel(yc + rotY, xc + rotX, col, pim);
- while (a*a*(y-.5) > b*b*(x+1)) {
+ while (a * a * (y - .5) > b * b * (x + 1)) {
if (d1 < 0) {
- d1 += b*b*(2*x+3);
+ d1 += b * b * (2 * x + 3);
++x;
} else {
- d1 += b*b*(2*x+3) + a*a*(-2*y+2);
+ d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2);
++x;
--y;
}
@@ -108,14 +112,14 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB,
rotY = (-matXY[2] * x + matXY[3] * y);
safePutPixel(yc + rotY, xc + rotX, col, pim);
}
- d2 = b*b*(x+.5)*(x+.5) + a*a*(y-1)*(y-1) - a*a*b*b;
+ d2 = b * b * (x + .5) * (x + .5) + a * a * (y - 1) * (y - 1) - a * a * b * b;
while (y > 0) {
if (d2 < 0) {
- d2 += b*b*(2*x+2) + a*a*(-2*y+3);
+ d2 += b * b * (2 * x + 2) + a * a * (-2 * y + 3);
--y;
++x;
} else {
- d2 += a*a*(-2*y+3);
+ d2 += a * a * (-2 * y + 3);
--y;
}
rotX = (matXY[0] * x + matXY[1] * y);
@@ -137,23 +141,23 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB,
// So it's better the use the Andres method.
// http://fr.wikipedia.org/wiki/Algorithme_de_tracé_de_cercle_d'Andres.
template <class Image, class Color>
-void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) {
- Image &im = *pim;
- if ( im.Contains(y + radius, x + radius)
- || im.Contains(y + radius, x - radius)
- || im.Contains(y - radius, x + radius)
- || im.Contains(y - radius, x - radius)) {
+void DrawCircle(int x, int y, int radius, const Color& col, Image* pim) {
+ Image& im = *pim;
+ if (im.Contains(y + radius, x + radius) ||
+ im.Contains(y + radius, x - radius) ||
+ im.Contains(y - radius, x + radius) ||
+ im.Contains(y - radius, x - radius)) {
int x1 = 0;
int y1 = radius;
int d = radius - 1;
while (y1 >= x1) {
// Draw the point for each octant.
- safePutPixel( y1 + y, x1 + x, col, pim);
- safePutPixel( x1 + y, y1 + x, col, pim);
- safePutPixel( y1 + y, -x1 + x, col, pim);
- safePutPixel( x1 + y, -y1 + x, col, pim);
- safePutPixel(-y1 + y, x1 + x, col, pim);
- safePutPixel(-x1 + y, y1 + x, col, pim);
+ safePutPixel(y1 + y, x1 + x, col, pim);
+ safePutPixel(x1 + y, y1 + x, col, pim);
+ safePutPixel(y1 + y, -x1 + x, col, pim);
+ safePutPixel(x1 + y, -y1 + x, col, pim);
+ safePutPixel(-y1 + y, x1 + x, col, pim);
+ safePutPixel(-x1 + y, y1 + x, col, pim);
safePutPixel(-y1 + y, -x1 + x, col, pim);
safePutPixel(-x1 + y, -y1 + x, col, pim);
if (d >= 2 * x1) {
@@ -163,7 +167,7 @@ void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) {
if (d <= 2 * (radius - y1)) {
d = d + 2 * y1 - 1;
y1 -= 1;
- } else {
+ } else {
d = d + 2 * (y1 - x1 - 1);
y1 -= 1;
x1 += 1;
@@ -175,8 +179,8 @@ void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) {
// Bresenham algorithm
template <class Image, class Color>
-void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) {
- Image &im = *pim;
+void DrawLine(int xa, int ya, int xb, int yb, const Color& col, Image* pim) {
+ Image& im = *pim;
// If one point is outside the image
// Replace the outside point by the intersection of the line and
@@ -185,35 +189,37 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) {
int width = pim->Width();
int height = pim->Height();
const bool xdir = xa < xb, ydir = ya < yb;
- float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb,
- &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
- &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
- &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
- &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
+ float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb, &xleft = xdir ? nx0 : nx1,
+ &yleft = xdir ? ny0 : ny1, &xright = xdir ? nx1 : nx0,
+ &yright = xdir ? ny1 : ny0, &xup = ydir ? nx0 : nx1,
+ &yup = ydir ? ny0 : ny1, &xdown = ydir ? nx1 : nx0,
+ &ydown = ydir ? ny1 : ny0;
- if (xright < 0 || xleft >= width) return;
+ if (xright < 0 || xleft >= width)
+ return;
if (xleft < 0) {
- yleft -= xleft*(yright - yleft)/(xright - xleft);
- xleft = 0;
+ yleft -= xleft * (yright - yleft) / (xright - xleft);
+ xleft = 0;
}
if (xright >= width) {
- yright -= (xright - width)*(yright - yleft)/(xright - xleft);
- xright = width - 1;
+ yright -= (xright - width) * (yright - yleft) / (xright - xleft);
+ xright = width - 1;
}
- if (ydown < 0 || yup >= height) return;
+ if (ydown < 0 || yup >= height)
+ return;
if (yup < 0) {
- xup -= yup*(xdown - xup)/(ydown - yup);
- yup = 0;
+ xup -= yup * (xdown - xup) / (ydown - yup);
+ yup = 0;
}
if (ydown >= height) {
- xdown -= (ydown - height)*(xdown - xup)/(ydown - yup);
- ydown = height - 1;
+ xdown -= (ydown - height) * (xdown - xup) / (ydown - yup);
+ ydown = height - 1;
}
- xa = (int) xleft;
- xb = (int) xright;
- ya = (int) yleft;
- yb = (int) yright;
+ xa = (int)xleft;
+ xb = (int)xright;
+ ya = (int)yleft;
+ yb = (int)yright;
}
int xbas, xhaut, ybas, yhaut;
@@ -241,7 +247,7 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) {
}
if (dy > 0) { // Positive slope will increment X.
incrmY = 1;
- } else { // Negative slope.
+ } else { // Negative slope.
incrmY = -1;
}
if (dx >= dy) {
@@ -255,9 +261,9 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) {
x += incrmX;
if (dp <= 0) { // Go in direction of the South Pixel.
dp += S;
- } else { // Go to the North.
+ } else { // Go to the North.
dp += N;
- y+=incrmY;
+ y += incrmY;
}
}
} else {
@@ -271,7 +277,7 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) {
y += incrmY;
if (dp <= 0) { // Go in direction of the South Pixel.
dp += S;
- } else { // Go to the North.
+ } else { // Go to the North.
dp += N;
x += incrmX;
}
diff --git a/intern/libmv/libmv/image/image_test.cc b/intern/libmv/libmv/image/image_test.cc
index 241f49f2244..a1730a9a55e 100644
--- a/intern/libmv/libmv/image/image_test.cc
+++ b/intern/libmv/libmv/image/image_test.cc
@@ -23,20 +23,20 @@
#include "libmv/image/image.h"
#include "testing/testing.h"
-using libmv::Image;
using libmv::Array3Df;
+using libmv::Image;
namespace {
TEST(Image, SimpleImageAccessors) {
- Array3Df *array = new Array3Df(2, 3);
+ Array3Df* array = new Array3Df(2, 3);
Image image(array);
EXPECT_EQ(array, image.AsArray3Df());
EXPECT_TRUE(NULL == image.AsArray3Du());
}
TEST(Image, MemorySizeInBytes) {
- Array3Df *array = new Array3Df(2, 3);
+ Array3Df* array = new Array3Df(2, 3);
Image image(array);
int size = sizeof(image) + array->MemorySizeInBytes();
EXPECT_EQ(size, image.MemorySizeInBytes());
diff --git a/intern/libmv/libmv/image/sample.h b/intern/libmv/libmv/image/sample.h
index 24eb9ccd57d..2b57baf27b9 100644
--- a/intern/libmv/libmv/image/sample.h
+++ b/intern/libmv/libmv/image/sample.h
@@ -26,17 +26,14 @@
namespace libmv {
/// Nearest neighbor interpolation.
-template<typename T>
-inline T SampleNearest(const Array3D<T> &image,
- float y, float x, int v = 0) {
+template <typename T>
+inline T SampleNearest(const Array3D<T>& image, float y, float x, int v = 0) {
const int i = int(round(y));
const int j = int(round(x));
return image(i, j, v);
}
-inline void LinearInitAxis(float x, int size,
- int *x1, int *x2,
- float *dx) {
+inline void LinearInitAxis(float x, int size, int* x1, int* x2, float* dx) {
const int ix = static_cast<int>(x);
if (ix < 0) {
*x1 = 0;
@@ -54,32 +51,32 @@ inline void LinearInitAxis(float x, int size,
}
/// Linear interpolation.
-template<typename T>
-inline T SampleLinear(const Array3D<T> &image, float y, float x, int v = 0) {
+template <typename T>
+inline T SampleLinear(const Array3D<T>& image, float y, float x, int v = 0) {
int x1, y1, x2, y2;
float dx, dy;
LinearInitAxis(y, image.Height(), &y1, &y2, &dy);
- LinearInitAxis(x, image.Width(), &x1, &x2, &dx);
+ LinearInitAxis(x, image.Width(), &x1, &x2, &dx);
const T im11 = image(y1, x1, v);
const T im12 = image(y1, x2, v);
const T im21 = image(y2, x1, v);
const T im22 = image(y2, x2, v);
- return T( dy * (dx * im11 + (1.0 - dx) * im12) +
+ return T(dy * (dx * im11 + (1.0 - dx) * im12) +
(1 - dy) * (dx * im21 + (1.0 - dx) * im22));
}
/// Linear interpolation, of all channels. The sample is assumed to have the
/// same size as the number of channels in image.
-template<typename T>
-inline void SampleLinear(const Array3D<T> &image, float y, float x, T *sample) {
+template <typename T>
+inline void SampleLinear(const Array3D<T>& image, float y, float x, T* sample) {
int x1, y1, x2, y2;
float dx, dy;
LinearInitAxis(y, image.Height(), &y1, &y2, &dy);
- LinearInitAxis(x, image.Width(), &x1, &x2, &dx);
+ LinearInitAxis(x, image.Width(), &x1, &x2, &dx);
for (int i = 0; i < image.Depth(); ++i) {
const T im11 = image(y1, x1, i);
@@ -87,7 +84,7 @@ inline void SampleLinear(const Array3D<T> &image, float y, float x, T *sample) {
const T im21 = image(y2, x1, i);
const T im22 = image(y2, x2, i);
- sample[i] = T( dy * (dx * im11 + (1.0 - dx) * im12) +
+ sample[i] = T(dy * (dx * im11 + (1.0 - dx) * im12) +
(1 - dy) * (dx * im21 + (1.0 - dx) * im22));
}
}
@@ -95,7 +92,7 @@ inline void SampleLinear(const Array3D<T> &image, float y, float x, T *sample) {
// Downsample all channels by 2. If the image has odd width or height, the last
// row or column is ignored.
// FIXME(MatthiasF): this implementation shouldn't be in an interface file
-inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) {
+inline void DownsampleChannelsBy2(const Array3Df& in, Array3Df* out) {
int height = in.Height() / 2;
int width = in.Width() / 2;
int depth = in.Depth();
@@ -106,10 +103,12 @@ inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) {
for (int r = 0; r < height; ++r) {
for (int c = 0; c < width; ++c) {
for (int k = 0; k < depth; ++k) {
+ // clang-format off
(*out)(r, c, k) = (in(2 * r, 2 * c, k) +
in(2 * r + 1, 2 * c, k) +
in(2 * r, 2 * c + 1, k) +
in(2 * r + 1, 2 * c + 1, k)) / 4.0f;
+ // clang-format on
}
}
}
@@ -117,11 +116,12 @@ inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) {
// Sample a region centered at x,y in image with size extending by half_width
// from x,y. Channels specifies the number of channels to sample from.
-inline void SamplePattern(const FloatImage &image,
- double x, double y,
- int half_width,
- int channels,
- FloatImage *sampled) {
+inline void SamplePattern(const FloatImage& image,
+ double x,
+ double y,
+ int half_width,
+ int channels,
+ FloatImage* sampled) {
sampled->Resize(2 * half_width + 1, 2 * half_width + 1, channels);
for (int r = -half_width; r <= half_width; ++r) {
for (int c = -half_width; c <= half_width; ++c) {
diff --git a/intern/libmv/libmv/image/sample_test.cc b/intern/libmv/libmv/image/sample_test.cc
index c8a0ce470c2..f1fb4c42c67 100644
--- a/intern/libmv/libmv/image/sample_test.cc
+++ b/intern/libmv/libmv/image/sample_test.cc
@@ -32,9 +32,9 @@ TEST(Image, Nearest) {
image(1, 0) = 2;
image(1, 1) = 3;
EXPECT_EQ(0, SampleNearest(image, -0.4f, -0.4f));
- EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f));
- EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f));
- EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f));
+ EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f));
+ EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f));
+ EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f));
}
TEST(Image, Linear) {
@@ -57,7 +57,7 @@ TEST(Image, DownsampleBy2) {
ASSERT_EQ(1, resampled_image.Height());
ASSERT_EQ(1, resampled_image.Width());
ASSERT_EQ(1, resampled_image.Depth());
- EXPECT_FLOAT_EQ(6./4., resampled_image(0, 0));
+ EXPECT_FLOAT_EQ(6. / 4., resampled_image(0, 0));
}
TEST(Image, DownsampleBy2MultiChannel) {
@@ -82,8 +82,8 @@ TEST(Image, DownsampleBy2MultiChannel) {
ASSERT_EQ(1, resampled_image.Height());
ASSERT_EQ(1, resampled_image.Width());
ASSERT_EQ(3, resampled_image.Depth());
- EXPECT_FLOAT_EQ((0+1+2+3)/4., resampled_image(0, 0, 0));
- EXPECT_FLOAT_EQ((5+6+7+8)/4., resampled_image(0, 0, 1));
- EXPECT_FLOAT_EQ((9+10+11+12)/4., resampled_image(0, 0, 2));
+ EXPECT_FLOAT_EQ((0 + 1 + 2 + 3) / 4., resampled_image(0, 0, 0));
+ EXPECT_FLOAT_EQ((5 + 6 + 7 + 8) / 4., resampled_image(0, 0, 1));
+ EXPECT_FLOAT_EQ((9 + 10 + 11 + 12) / 4., resampled_image(0, 0, 2));
}
} // namespace
diff --git a/intern/libmv/libmv/image/tuple.h b/intern/libmv/libmv/image/tuple.h
index c8dc36f2e18..447bf0cc81c 100644
--- a/intern/libmv/libmv/image/tuple.h
+++ b/intern/libmv/libmv/image/tuple.h
@@ -34,10 +34,14 @@ class Tuple {
Tuple(T initial_value) { Reset(initial_value); }
template <typename D>
- Tuple(D *values) { Reset(values); }
+ Tuple(D* values) {
+ Reset(values);
+ }
template <typename D>
- Tuple(const Tuple<D, N> &b) { Reset(b); }
+ Tuple(const Tuple<D, N>& b) {
+ Reset(b);
+ }
template <typename D>
Tuple& operator=(const Tuple<D, N>& b) {
@@ -46,30 +50,32 @@ class Tuple {
}
template <typename D>
- void Reset(const Tuple<D, N>& b) { Reset(b.Data()); }
+ void Reset(const Tuple<D, N>& b) {
+ Reset(b.Data());
+ }
template <typename D>
- void Reset(D *values) {
- for (int i = 0;i < N; i++) {
+ void Reset(D* values) {
+ for (int i = 0; i < N; i++) {
data_[i] = T(values[i]);
}
}
// Set all tuple values to the same thing.
void Reset(T value) {
- for (int i = 0;i < N; i++) {
+ for (int i = 0; i < N; i++) {
data_[i] = value;
}
}
// Pointer to the first element.
- T *Data() { return &data_[0]; }
- const T *Data() const { return &data_[0]; }
+ T* Data() { return &data_[0]; }
+ const T* Data() const { return &data_[0]; }
- T &operator()(int i) { return data_[i]; }
- const T &operator()(int i) const { return data_[i]; }
+ T& operator()(int i) { return data_[i]; }
+ const T& operator()(int i) const { return data_[i]; }
- bool operator==(const Tuple<T, N> &other) const {
+ bool operator==(const Tuple<T, N>& other) const {
for (int i = 0; i < N; ++i) {
if ((*this)(i) != other(i)) {
return false;
@@ -77,9 +83,7 @@ class Tuple {
}
return true;
}
- bool operator!=(const Tuple<T, N> &other) const {
- return !(*this == other);
- }
+ bool operator!=(const Tuple<T, N>& other) const { return !(*this == other); }
private:
T data_[N];
diff --git a/intern/libmv/libmv/multiview/conditioning.cc b/intern/libmv/libmv/multiview/conditioning.cc
index 0afbf119ea3..2f4bf653ca0 100644
--- a/intern/libmv/libmv/multiview/conditioning.cc
+++ b/intern/libmv/libmv/multiview/conditioning.cc
@@ -24,7 +24,7 @@
namespace libmv {
// HZ 4.4.4 pag.109: Point conditioning (non isotropic)
-void PreconditionerFromPoints(const Mat &points, Mat3 *T) {
+void PreconditionerFromPoints(const Mat& points, Mat3* T) {
Vec mean, variance;
MeanAndVarianceAlongRows(points, &mean, &variance);
@@ -38,12 +38,14 @@ void PreconditionerFromPoints(const Mat &points, Mat3 *T) {
if (variance(1) < 1e-8)
yfactor = mean(1) = 1.0;
+ // clang-format off
*T << xfactor, 0, -xfactor * mean(0),
0, yfactor, -yfactor * mean(1),
0, 0, 1;
+ // clang-format on
}
// HZ 4.4.4 pag.107: Point conditioning (isotropic)
-void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) {
+void IsotropicPreconditionerFromPoints(const Mat& points, Mat3* T) {
Vec mean, variance;
MeanAndVarianceAlongRows(points, &mean, &variance);
@@ -57,14 +59,16 @@ void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) {
mean.setOnes();
}
+ // clang-format off
*T << factor, 0, -factor * mean(0),
0, factor, -factor * mean(1),
0, 0, 1;
+ // clang-format on
}
-void ApplyTransformationToPoints(const Mat &points,
- const Mat3 &T,
- Mat *transformed_points) {
+void ApplyTransformationToPoints(const Mat& points,
+ const Mat3& T,
+ Mat* transformed_points) {
int n = points.cols();
transformed_points->resize(2, n);
Mat3X p(3, n);
@@ -73,26 +77,24 @@ void ApplyTransformationToPoints(const Mat &points,
HomogeneousToEuclidean(p, transformed_points);
}
-void NormalizePoints(const Mat &points,
- Mat *normalized_points,
- Mat3 *T) {
+void NormalizePoints(const Mat& points, Mat* normalized_points, Mat3* T) {
PreconditionerFromPoints(points, T);
ApplyTransformationToPoints(points, *T, normalized_points);
}
-void NormalizeIsotropicPoints(const Mat &points,
- Mat *normalized_points,
- Mat3 *T) {
+void NormalizeIsotropicPoints(const Mat& points,
+ Mat* normalized_points,
+ Mat3* T) {
IsotropicPreconditionerFromPoints(points, T);
ApplyTransformationToPoints(points, *T, normalized_points);
}
// Denormalize the results. See HZ page 109.
-void UnnormalizerT::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) {
+void UnnormalizerT::Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H) {
*H = T2.transpose() * (*H) * T1;
}
-void UnnormalizerI::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) {
+void UnnormalizerI::Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H) {
*H = T2.inverse() * (*H) * T1;
}
diff --git a/intern/libmv/libmv/multiview/conditioning.h b/intern/libmv/libmv/multiview/conditioning.h
index 8f3e3a76070..876c5af48e6 100644
--- a/intern/libmv/libmv/multiview/conditioning.h
+++ b/intern/libmv/libmv/multiview/conditioning.h
@@ -26,32 +26,30 @@
namespace libmv {
// Point conditioning (non isotropic)
-void PreconditionerFromPoints(const Mat &points, Mat3 *T);
+void PreconditionerFromPoints(const Mat& points, Mat3* T);
// Point conditioning (isotropic)
-void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T);
+void IsotropicPreconditionerFromPoints(const Mat& points, Mat3* T);
-void ApplyTransformationToPoints(const Mat &points,
- const Mat3 &T,
- Mat *transformed_points);
+void ApplyTransformationToPoints(const Mat& points,
+ const Mat3& T,
+ Mat* transformed_points);
-void NormalizePoints(const Mat &points,
- Mat *normalized_points,
- Mat3 *T);
+void NormalizePoints(const Mat& points, Mat* normalized_points, Mat3* T);
-void NormalizeIsotropicPoints(const Mat &points,
- Mat *normalized_points,
- Mat3 *T);
+void NormalizeIsotropicPoints(const Mat& points,
+ Mat* normalized_points,
+ Mat3* T);
/// Use inverse for unnormalize
struct UnnormalizerI {
// Denormalize the results. See HZ page 109.
- static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H);
+ static void Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H);
};
/// Use transpose for unnormalize
struct UnnormalizerT {
// Denormalize the results. See HZ page 109.
- static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H);
+ static void Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H);
};
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/euclidean_resection.cc b/intern/libmv/libmv/multiview/euclidean_resection.cc
index 16a1a0caafa..249d7ebef3d 100644
--- a/intern/libmv/libmv/multiview/euclidean_resection.cc
+++ b/intern/libmv/libmv/multiview/euclidean_resection.cc
@@ -23,8 +23,8 @@
#include <cmath>
#include <limits>
-#include <Eigen/SVD>
#include <Eigen/Geometry>
+#include <Eigen/SVD>
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
@@ -35,9 +35,10 @@ namespace euclidean_resection {
typedef unsigned int uint;
-bool EuclideanResection(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t,
+bool EuclideanResection(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t,
ResectionMethod method) {
switch (method) {
case RESECTION_ANSAR_DANIILIDIS:
@@ -49,20 +50,20 @@ bool EuclideanResection(const Mat2X &x_camera,
case RESECTION_PPNP:
return EuclideanResectionPPnP(x_camera, X_world, R, t);
break;
- default:
- LOG(FATAL) << "Unknown resection method.";
+ default: LOG(FATAL) << "Unknown resection method.";
}
return false;
}
-bool EuclideanResection(const Mat &x_image,
- const Mat3X &X_world,
- const Mat3 &K,
- Mat3 *R, Vec3 *t,
+bool EuclideanResection(const Mat& x_image,
+ const Mat3X& X_world,
+ const Mat3& K,
+ Mat3* R,
+ Vec3* t,
ResectionMethod method) {
CHECK(x_image.rows() == 2 || x_image.rows() == 3)
- << "Invalid size for x_image: "
- << x_image.rows() << "x" << x_image.cols();
+ << "Invalid size for x_image: " << x_image.rows() << "x"
+ << x_image.cols();
Mat2X x_camera;
if (x_image.rows() == 2) {
@@ -73,18 +74,15 @@ bool EuclideanResection(const Mat &x_image,
return EuclideanResection(x_camera, X_world, R, t, method);
}
-void AbsoluteOrientation(const Mat3X &X,
- const Mat3X &Xp,
- Mat3 *R,
- Vec3 *t) {
+void AbsoluteOrientation(const Mat3X& X, const Mat3X& Xp, Mat3* R, Vec3* t) {
int num_points = X.cols();
- Vec3 C = X.rowwise().sum() / num_points; // Centroid of X.
+ Vec3 C = X.rowwise().sum() / num_points; // Centroid of X.
Vec3 Cp = Xp.rowwise().sum() / num_points; // Centroid of Xp.
// Normalize the two point sets.
Mat3X Xn(3, num_points), Xpn(3, num_points);
for (int i = 0; i < num_points; ++i) {
- Xn.col(i) = X.col(i) - C;
+ Xn.col(i) = X.col(i) - C;
Xpn.col(i) = Xp.col(i) - Cp;
}
@@ -100,10 +98,12 @@ void AbsoluteOrientation(const Mat3X &X,
double Szy = Xn.row(2).dot(Xpn.row(1));
Mat4 N;
+ // clang-format off
N << Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx,
Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz,
Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy,
Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz;
+ // clang-format on
// Find the unit quaternion q that maximizes qNq. It is the eigenvector
// corresponding to the lagest eigenvalue.
@@ -118,6 +118,7 @@ void AbsoluteOrientation(const Mat3X &X,
double q1q3 = q(1) * q(3);
double q2q3 = q(2) * q(3);
+ // clang-format off
(*R) << qq(0) + qq(1) - qq(2) - qq(3),
2 * (q1q2 - q0q3),
2 * (q1q3 + q0q2),
@@ -127,6 +128,7 @@ void AbsoluteOrientation(const Mat3X &X,
2 * (q1q3 - q0q2),
2 * (q2q3 + q0q1),
qq(0) - qq(1) - qq(2) + qq(3);
+ // clang-format on
// Fix the handedness of the R matrix.
if (R->determinant() < 0) {
@@ -176,9 +178,7 @@ static int Sign(double value) {
// Lambda to create the constraints in equation (5) in "Linear Pose Estimation
// from Points or Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no.
// 5.
-static Vec MatrixToConstraint(const Mat &A,
- int num_k_columns,
- int num_lambda) {
+static Vec MatrixToConstraint(const Mat& A, int num_k_columns, int num_lambda) {
Vec C(num_k_columns);
C.setZero();
int idx = 0;
@@ -195,17 +195,17 @@ static Vec MatrixToConstraint(const Mat &A,
}
// Normalizes the columns of vectors.
-static void NormalizeColumnVectors(Mat3X *vectors) {
+static void NormalizeColumnVectors(Mat3X* vectors) {
int num_columns = vectors->cols();
for (int i = 0; i < num_columns; ++i) {
vectors->col(i).normalize();
}
}
-void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R,
- Vec3 *t) {
+void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t) {
CHECK(x_camera.cols() == X_world.cols());
CHECK(x_camera.cols() > 3);
@@ -229,14 +229,14 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
// them into the M matrix (8). Also store the initial (i, j) indices.
int row = 0;
for (int i = 0; i < num_points; ++i) {
- for (int j = i+1; j < num_points; ++j) {
+ for (int j = i + 1; j < num_points; ++j) {
M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j));
M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i));
M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j));
Vec3 Xdiff = X_world.col(i) - X_world.col(j);
double center_to_point_distance = Xdiff.norm();
M(row, num_m_columns - 1) =
- - center_to_point_distance * center_to_point_distance;
+ -center_to_point_distance * center_to_point_distance;
ij_index(row, 0) = i;
ij_index(row, 1) = j;
++row;
@@ -246,17 +246,17 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
}
int num_lambda = num_points + 1; // Dimension of the null space of M.
- Mat V = M.jacobiSvd(Eigen::ComputeFullV).matrixV().block(0,
- num_m_rows,
- num_m_columns,
- num_lambda);
+ Mat V = M.jacobiSvd(Eigen::ComputeFullV)
+ .matrixV()
+ .block(0, num_m_rows, num_m_columns, num_lambda);
// TODO(vess): The number of constraint equations in K (num_k_rows) must be
// (num_points + 1) * (num_points + 2)/2. This creates a performance issue
// for more than 4 points. It is fine for 4 points at the moment with 18
// instead of 15 equations.
- int num_k_rows = num_m_rows + num_points *
- (num_points*(num_points-1)/2 - num_points+1);
+ int num_k_rows =
+ num_m_rows +
+ num_points * (num_points * (num_points - 1) / 2 - num_points + 1);
int num_k_columns = num_lambda * (num_lambda + 1) / 2;
Mat K(num_k_rows, num_k_columns);
K.setZero();
@@ -275,8 +275,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
int idx4 = IJToPointIndex(i, k, num_points);
K.row(counter_k_row) =
- MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)-
- V.row(idx3).transpose() * V.row(idx4),
+ MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2) -
+ V.row(idx3).transpose() * V.row(idx4),
num_k_columns,
num_lambda);
++counter_k_row;
@@ -296,8 +296,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
int idx4 = IJToPointIndex(i, k, num_points);
K.row(counter_k_row) =
- MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)-
- V.row(idx3).transpose() * V.row(idx4),
+ MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2) -
+ V.row(idx3).transpose() * V.row(idx4),
num_k_columns,
num_lambda);
++counter_k_row;
@@ -317,14 +317,12 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
}
}
// Ensure positiveness of the largest value corresponding to lambda_ii.
- L_sq = L_sq * Sign(L_sq(IJToIndex(max_L_sq_index,
- max_L_sq_index,
- num_lambda)));
+ L_sq =
+ L_sq * Sign(L_sq(IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda)));
Vec L(num_lambda);
- L(max_L_sq_index) = sqrt(L_sq(IJToIndex(max_L_sq_index,
- max_L_sq_index,
- num_lambda)));
+ L(max_L_sq_index) =
+ sqrt(L_sq(IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda)));
for (int i = 0; i < num_lambda; ++i) {
if (i != max_L_sq_index) {
@@ -353,9 +351,9 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
}
// Selects 4 virtual control points using mean and PCA.
-static void SelectControlPoints(const Mat3X &X_world,
- Mat *X_centered,
- Mat34 *X_control_points) {
+static void SelectControlPoints(const Mat3X& X_world,
+ Mat* X_centered,
+ Mat34* X_control_points) {
size_t num_points = X_world.cols();
// The first virtual control point, C0, is the centroid.
@@ -379,13 +377,13 @@ static void SelectControlPoints(const Mat3X &X_world,
}
// Computes the barycentric coordinates for all real points
-static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered,
- const Mat34 &X_control_points,
- Mat4X *alphas) {
+static void ComputeBarycentricCoordinates(const Mat3X& X_world_centered,
+ const Mat34& X_control_points,
+ Mat4X* alphas) {
size_t num_points = X_world_centered.cols();
Mat3 C2;
for (size_t c = 1; c < 4; c++) {
- C2.col(c-1) = X_control_points.col(c) - X_control_points.col(0);
+ C2.col(c - 1) = X_control_points.col(c) - X_control_points.col(0);
}
Mat3 C2inv = C2.inverse();
@@ -401,14 +399,15 @@ static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered,
// Estimates the coordinates of all real points in the camera coordinate frame
static void ComputePointsCoordinatesInCameraFrame(
- const Mat4X &alphas,
- const Vec4 &betas,
- const Eigen::Matrix<double, 12, 12> &U,
- Mat3X *X_camera) {
+ const Mat4X& alphas,
+ const Vec4& betas,
+ const Eigen::Matrix<double, 12, 12>& U,
+ Mat3X* X_camera) {
size_t num_points = alphas.cols();
// Estimates the control points in the camera reference frame.
- Mat34 C2b; C2b.setZero();
+ Mat34 C2b;
+ C2b.setZero();
for (size_t cu = 0; cu < 4; cu++) {
for (size_t c = 0; c < 4; c++) {
C2b.col(c) += betas(cu) * U.block(11 - cu, c * 3, 1, 3).transpose();
@@ -436,9 +435,10 @@ static void ComputePointsCoordinatesInCameraFrame(
}
}
-bool EuclideanResectionEPnP(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t) {
+bool EuclideanResectionEPnP(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t) {
CHECK(x_camera.cols() == X_world.cols());
CHECK(x_camera.cols() > 3);
size_t num_points = X_world.cols();
@@ -462,6 +462,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
double a3 = alphas(3, c);
double ui = x_camera(0, c);
double vi = x_camera(1, c);
+ // clang-format off
M.block(2*c, 0, 2, 12) << a0, 0,
a0*(-ui), a1, 0,
a1*(-ui), a2, 0,
@@ -471,10 +472,11 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
a1, a1*(-vi), 0,
a2, a2*(-vi), 0,
a3, a3*(-vi);
+ // clang-format on
}
// TODO(julien): Avoid the transpose by rewriting the u2.block() calls.
- Eigen::JacobiSVD<Mat> MtMsvd(M.transpose()*M, Eigen::ComputeFullU);
+ Eigen::JacobiSVD<Mat> MtMsvd(M.transpose() * M, Eigen::ComputeFullU);
Eigen::Matrix<double, 12, 12> u2 = MtMsvd.matrixU().transpose();
// Estimate the L matrix.
@@ -495,21 +497,22 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3);
dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3);
dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3);
- dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3);
- dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3);
- dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3);
- dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3);
- dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3);
- dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3);
- dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3);
- dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3);
- dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3);
- dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3);
- dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3);
- dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3);
+ dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3);
+ dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3);
+ dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3);
+ dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3);
+ dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3);
+ dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3);
+ dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3);
+ dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3);
+ dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3);
+ dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3);
+ dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3);
+ dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3);
Eigen::Matrix<double, 6, 10> L;
for (size_t r = 0; r < 6; r++) {
+ // clang-format off
L.row(r) << dv1.row(r).dot(dv1.row(r)),
2.0 * dv1.row(r).dot(dv2.row(r)),
dv2.row(r).dot(dv2.row(r)),
@@ -520,19 +523,23 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
2.0 * dv2.row(r).dot(dv4.row(r)),
2.0 * dv3.row(r).dot(dv4.row(r)),
dv4.row(r).dot(dv4.row(r));
+ // clang-format on
}
Vec6 rho;
+ // clang-format off
rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(),
(X_control_points.col(0) - X_control_points.col(2)).squaredNorm(),
(X_control_points.col(0) - X_control_points.col(3)).squaredNorm(),
(X_control_points.col(1) - X_control_points.col(2)).squaredNorm(),
(X_control_points.col(1) - X_control_points.col(3)).squaredNorm(),
(X_control_points.col(2) - X_control_points.col(3)).squaredNorm();
+ // clang-format on
// There are three possible solutions based on the three approximations of L
// (betas). Below, each one is solved for then the best one is chosen.
Mat3X X_camera;
- Mat3 K; K.setIdentity();
+ Mat3 K;
+ K.setIdentity();
vector<Mat3> Rs(3);
vector<Vec3> ts(3);
Vec rmse(3);
@@ -546,7 +553,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
//
// TODO(keir): Decide if setting this to infinity, effectively disabling the
// check, is the right approach. So far this seems the case.
- double kSuccessThreshold = std::numeric_limits<double>::max();
+ double kSuccessThreshold = std::numeric_limits<double>::max();
// Find the first possible solution for R, t corresponding to:
// Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
@@ -563,7 +570,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
if (b4(0) < 0) {
b4 = -b4;
}
- b4(0) = std::sqrt(b4(0));
+ b4(0) = std::sqrt(b4(0));
betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0);
ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
AbsoluteOrientation(X_world, X_camera, &Rs[0], &ts[0]);
@@ -669,12 +676,12 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
// TODO(julien): Improve the solutions with non-linear refinement.
return true;
}
-
+
/*
-
+
Straight from the paper:
http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf
-
+
function [R T] = ppnp(P,S,tol)
% input
% P : matrix (nx3) image coordinates in camera reference [u v 1]
@@ -708,33 +715,34 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
end
T = -R*c;
end
-
+
*/
// TODO(keir): Re-do all the variable names and add comments matching the paper.
// This implementation has too much of the terseness of the original. On the
// other hand, it did work on the first try.
-bool EuclideanResectionPPnP(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t) {
+bool EuclideanResectionPPnP(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t) {
int n = x_camera.cols();
Mat Z = Mat::Zero(n, n);
Vec e = Vec::Ones(n);
Mat A = Mat::Identity(n, n) - (e * e.transpose() / n);
Vec II = e / n;
-
+
Mat P(n, 3);
P.col(0) = x_camera.row(0);
P.col(1) = x_camera.row(1);
P.col(2).setConstant(1.0);
-
+
Mat S = X_world.transpose();
-
+
double error = std::numeric_limits<double>::infinity();
Mat E_old = 1000 * Mat::Ones(n, 3);
-
+
Vec3 c;
Mat E(n, 3);
-
+
int iteration = 0;
double tolerance = 1e-5;
// TODO(keir): The limit of 100 can probably be reduced, but this will require
@@ -748,20 +756,21 @@ bool EuclideanResectionPPnP(const Mat2X &x_camera,
s << 1, 1, (U * VT).determinant();
*R = U * s.asDiagonal() * VT;
Mat PR = P * *R; // n x 3
- c = (S - Z*PR).transpose() * II;
- Mat Y = S - e*c.transpose(); // n x 3
- Vec Zmindiag = (PR * Y.transpose()).diagonal()
- .cwiseQuotient(P.rowwise().squaredNorm());
+ c = (S - Z * PR).transpose() * II;
+ Mat Y = S - e * c.transpose(); // n x 3
+ Vec Zmindiag = (PR * Y.transpose())
+ .diagonal()
+ .cwiseQuotient(P.rowwise().squaredNorm());
for (int i = 0; i < n; ++i) {
Zmindiag[i] = std::max(Zmindiag[i], 0.0);
}
Z = Zmindiag.asDiagonal();
- E = Y - Z*PR;
+ E = Y - Z * PR;
error = (E - E_old).norm();
LG << "PPnP error(" << (iteration++) << "): " << error;
E_old = E;
}
- *t = -*R*c;
+ *t = -*R * c;
// TODO(keir): Figure out what the failure cases are. Is it too many
// iterations? Spend some time going through the math figuring out if there
@@ -769,6 +778,5 @@ bool EuclideanResectionPPnP(const Mat2X &x_camera,
return true;
}
-
-} // namespace resection
+} // namespace euclidean_resection
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/euclidean_resection.h b/intern/libmv/libmv/multiview/euclidean_resection.h
index 28eae92611c..3c4c3979ff6 100644
--- a/intern/libmv/libmv/multiview/euclidean_resection.h
+++ b/intern/libmv/libmv/multiview/euclidean_resection.h
@@ -21,8 +21,8 @@
#ifndef LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_
#define LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_
-#include "libmv/numeric/numeric.h"
#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
namespace euclidean_resection {
@@ -33,7 +33,7 @@ enum ResectionMethod {
// The "EPnP" algorithm by Lepetit et al.
// http://cvlab.epfl.ch/~lepetit/papers/lepetit_ijcv08.pdf
RESECTION_EPNP,
-
+
// The Procrustes PNP algorithm ("PPnP")
// http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf
RESECTION_PPNP
@@ -50,9 +50,10 @@ enum ResectionMethod {
* \param t Solution for the camera translation vector
* \param method The resection method to use.
*/
-bool EuclideanResection(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t,
+bool EuclideanResection(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t,
ResectionMethod method = RESECTION_EPNP);
/**
@@ -68,10 +69,11 @@ bool EuclideanResection(const Mat2X &x_camera,
* \param t Solution for the camera translation vector
* \param method Resection method
*/
-bool EuclideanResection(const Mat &x_image,
- const Mat3X &X_world,
- const Mat3 &K,
- Mat3 *R, Vec3 *t,
+bool EuclideanResection(const Mat& x_image,
+ const Mat3X& X_world,
+ const Mat3& K,
+ Mat3* R,
+ Vec3* t,
ResectionMethod method = RESECTION_EPNP);
/**
@@ -84,10 +86,7 @@ bool EuclideanResection(const Mat &x_image,
* Horn, Hilden, "Closed-form solution of absolute orientation using
* orthonormal matrices"
*/
-void AbsoluteOrientation(const Mat3X &X,
- const Mat3X &Xp,
- Mat3 *R,
- Vec3 *t);
+void AbsoluteOrientation(const Mat3X& X, const Mat3X& Xp, Mat3* R, Vec3* t);
/**
* Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
@@ -102,9 +101,10 @@ void AbsoluteOrientation(const Mat3X &X,
* This is the algorithm described in: "Linear Pose Estimation from Points or
* Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. 5.
*/
-void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t);
+void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t);
/**
* Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
* more 3D points and their images.
@@ -120,9 +120,10 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
* and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2
* \note: the non-linear optimization is not implemented here.
*/
-bool EuclideanResectionEPnP(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t);
+bool EuclideanResectionEPnP(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t);
/**
* Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
@@ -137,12 +138,12 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
* Straight from the paper:
* http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf
*/
-bool EuclideanResectionPPnP(const Mat2X &x_camera,
- const Mat3X &X_world,
- Mat3 *R, Vec3 *t);
+bool EuclideanResectionPPnP(const Mat2X& x_camera,
+ const Mat3X& X_world,
+ Mat3* R,
+ Vec3* t);
} // namespace euclidean_resection
} // namespace libmv
-
#endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */
diff --git a/intern/libmv/libmv/multiview/euclidean_resection_test.cc b/intern/libmv/libmv/multiview/euclidean_resection_test.cc
index 378837d3d2d..3bb8e6e1710 100644
--- a/intern/libmv/libmv/multiview/euclidean_resection_test.cc
+++ b/intern/libmv/libmv/multiview/euclidean_resection_test.cc
@@ -19,9 +19,9 @@
// IN THE SOFTWARE.
#include "libmv/multiview/euclidean_resection.h"
-#include "libmv/numeric/numeric.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
#include "testing/testing.h"
using namespace libmv::euclidean_resection;
@@ -33,10 +33,10 @@ static void CreateCameraSystem(const Mat3& KK,
const Vec& X_distances,
const Mat3& R_input,
const Vec3& T_input,
- Mat2X *x_camera,
- Mat3X *X_world,
- Mat3 *R_expected,
- Vec3 *T_expected) {
+ Mat2X* x_camera,
+ Mat3X* X_world,
+ Mat3* R_expected,
+ Vec3* T_expected) {
int num_points = x_image.cols();
Mat3X x_unit_cam(3, num_points);
@@ -76,9 +76,9 @@ TEST(AbsoluteOrientation, QuaternionSolution) {
// Create a random translation and rotation.
Mat3 R_input;
- R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
+ R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) *
+ Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) *
+ Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
Vec3 t_input;
t_input.setRandom();
@@ -109,26 +109,29 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
image_dimensions << 1600, 1200;
Mat3 KK;
+ // clang-format off
KK << 2796, 0, 804,
0 , 2796, 641,
0, 0, 1;
+ // clang-format on
// The real image points.
int num_points = 4;
Mat3X x_image(3, num_points);
+ // clang-format off
x_image << 1164.06, 734.948, 749.599, 430.727,
681.386, 844.59, 496.315, 580.775,
1, 1, 1, 1;
-
+ // clang-format on
// A vector of the 4 distances to the 3D points.
Vec X_distances = 100 * Vec::Random(num_points).array().abs();
// Create the random camera motion R and t that resection should recover.
Mat3 R_input;
- R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
+ R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) *
+ Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) *
+ Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
Vec3 T_input;
T_input.setRandom();
@@ -140,15 +143,21 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
Vec3 T_expected;
Mat3X X_world;
Mat2X x_camera;
- CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
- &x_camera, &X_world, &R_expected, &T_expected);
+ CreateCameraSystem(KK,
+ x_image,
+ X_distances,
+ R_input,
+ T_input,
+ &x_camera,
+ &X_world,
+ &R_expected,
+ &T_expected);
// Finally, run the code under test.
Mat3 R_output;
Vec3 T_output;
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_ANSAR_DANIILIDIS);
+ EuclideanResection(
+ x_camera, X_world, &R_output, &T_output, RESECTION_ANSAR_DANIILIDIS);
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
@@ -173,9 +182,11 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
// TODO(jmichot): Reduce the code duplication here with the code above.
TEST(EuclideanResection, Points6AllRandomInput) {
Mat3 KK;
+ // clang-format off
KK << 2796, 0, 804,
0 , 2796, 641,
0, 0, 1;
+ // clang-format on
// Create random image points for a 1600x1200 image.
int w = 1600;
@@ -192,9 +203,9 @@ TEST(EuclideanResection, Points6AllRandomInput) {
// Create the random camera motion R and t that resection should recover.
Mat3 R_input;
- R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
+ R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) *
+ Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) *
+ Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
Vec3 T_input;
T_input.setRandom();
@@ -204,33 +215,36 @@ TEST(EuclideanResection, Points6AllRandomInput) {
Mat3 R_expected;
Vec3 T_expected;
Mat3X X_world;
- CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
- &x_camera, &X_world, &R_expected, &T_expected);
+ CreateCameraSystem(KK,
+ x_image,
+ X_distances,
+ R_input,
+ T_input,
+ &x_camera,
+ &X_world,
+ &R_expected,
+ &T_expected);
// Test each of the resection methods.
{
Mat3 R_output;
Vec3 T_output;
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_ANSAR_DANIILIDIS);
+ EuclideanResection(
+ x_camera, X_world, &R_output, &T_output, RESECTION_ANSAR_DANIILIDIS);
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
}
{
Mat3 R_output;
Vec3 T_output;
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_EPNP);
+ EuclideanResection(x_camera, X_world, &R_output, &T_output, RESECTION_EPNP);
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
}
{
Mat3 R_output;
Vec3 T_output;
- EuclideanResection(x_image, X_world, KK,
- &R_output, &T_output);
+ EuclideanResection(x_image, X_world, KK, &R_output, &T_output);
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
}
diff --git a/intern/libmv/libmv/multiview/fundamental.cc b/intern/libmv/libmv/multiview/fundamental.cc
index ea8594c8cc0..c8c94ecd7bb 100644
--- a/intern/libmv/libmv/multiview/fundamental.cc
+++ b/intern/libmv/libmv/multiview/fundamental.cc
@@ -22,15 +22,15 @@
#include "ceres/ceres.h"
#include "libmv/logging/logging.h"
-#include "libmv/numeric/numeric.h"
-#include "libmv/numeric/poly.h"
#include "libmv/multiview/conditioning.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/triangulation.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/poly.h"
namespace libmv {
-static void EliminateRow(const Mat34 &P, int row, Mat *X) {
+static void EliminateRow(const Mat34& P, int row, Mat* X) {
X->resize(2, 4);
int first_row = (row + 1) % 3;
@@ -42,7 +42,7 @@ static void EliminateRow(const Mat34 &P, int row, Mat *X) {
}
}
-void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) {
+void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2) {
*P1 << Mat3::Identity(), Vec3::Zero();
Vec3 e2;
Mat3 Ft = F.transpose();
@@ -51,7 +51,7 @@ void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) {
}
// Addapted from vgg_F_from_P.
-void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) {
+void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F) {
Mat X[3];
Mat Y[3];
Mat XY;
@@ -71,7 +71,7 @@ void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) {
// HZ 11.1 pag.279 (x1 = x, x2 = x')
// http://www.cs.unc.edu/~marc/tutorial/node54.html
-static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) {
+static double EightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) {
DCHECK_EQ(x1.rows(), 2);
DCHECK_GE(x1.cols(), 8);
DCHECK_EQ(x1.rows(), x2.rows());
@@ -98,7 +98,7 @@ static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) {
}
// HZ 11.1.1 pag.280
-void EnforceFundamentalRank2Constraint(Mat3 *F) {
+void EnforceFundamentalRank2Constraint(Mat3* F) {
Eigen::JacobiSVD<Mat3> USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV);
Vec3 d = USV.singularValues();
d(2) = 0.0;
@@ -106,9 +106,7 @@ void EnforceFundamentalRank2Constraint(Mat3 *F) {
}
// HZ 11.2 pag.281 (x1 = x, x2 = x')
-double NormalizedEightPointSolver(const Mat &x1,
- const Mat &x2,
- Mat3 *F) {
+double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) {
DCHECK_EQ(x1.rows(), 2);
DCHECK_GE(x1.cols(), 8);
DCHECK_EQ(x1.rows(), x2.rows());
@@ -135,9 +133,9 @@ double NormalizedEightPointSolver(const Mat &x1,
// Seven-point algorithm.
// http://www.cs.unc.edu/~marc/tutorial/node55.html
-double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- std::vector<Mat3> *F) {
+double FundamentalFrom7CorrespondencesLinear(const Mat& x1,
+ const Mat& x2,
+ std::vector<Mat3>* F) {
DCHECK_EQ(x1.rows(), 2);
DCHECK_EQ(x1.cols(), 7);
DCHECK_EQ(x1.rows(), x2.rows());
@@ -169,25 +167,29 @@ double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
// Then, use the condition det(F) = 0 to determine F. In other words, solve
// det(F1 + a*F2) = 0 for a.
- double a = F1(0, 0), j = F2(0, 0),
- b = F1(0, 1), k = F2(0, 1),
- c = F1(0, 2), l = F2(0, 2),
- d = F1(1, 0), m = F2(1, 0),
- e = F1(1, 1), n = F2(1, 1),
- f = F1(1, 2), o = F2(1, 2),
- g = F1(2, 0), p = F2(2, 0),
- h = F1(2, 1), q = F2(2, 1),
- i = F1(2, 2), r = F2(2, 2);
+ double a = F1(0, 0), j = F2(0, 0);
+ double b = F1(0, 1), k = F2(0, 1);
+ double c = F1(0, 2), l = F2(0, 2);
+ double d = F1(1, 0), m = F2(1, 0);
+ double e = F1(1, 1), n = F2(1, 1);
+ double f = F1(1, 2), o = F2(1, 2);
+ double g = F1(2, 0), p = F2(2, 0);
+ double h = F1(2, 1), q = F2(2, 1);
+ double i = F1(2, 2), r = F2(2, 2);
// Run fundamental_7point_coeffs.py to get the below coefficients.
// The coefficients are in ascending powers of alpha, i.e. P[N]*x^N.
double P[4] = {
- a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g,
- a*e*r + a*i*n + b*f*p + b*g*o + c*d*q + c*h*m + d*h*l + e*i*j + f*g*k -
- a*f*q - a*h*o - b*d*r - b*i*m - c*e*p - c*g*n - d*i*k - e*g*l - f*h*j,
- a*n*r + b*o*p + c*m*q + d*l*q + e*j*r + f*k*p + g*k*o + h*l*m + i*j*n -
- a*o*q - b*m*r - c*n*p - d*k*r - e*l*p - f*j*q - g*l*n - h*j*o - i*k*m,
- j*n*r + k*o*p + l*m*q - j*o*q - k*m*r - l*n*p,
+ a * e * i + b * f * g + c * d * h - a * f * h - b * d * i - c * e * g,
+ a * e * r + a * i * n + b * f * p + b * g * o + c * d * q + c * h * m +
+ d * h * l + e * i * j + f * g * k - a * f * q - a * h * o -
+ b * d * r - b * i * m - c * e * p - c * g * n - d * i * k -
+ e * g * l - f * h * j,
+ a * n * r + b * o * p + c * m * q + d * l * q + e * j * r + f * k * p +
+ g * k * o + h * l * m + i * j * n - a * o * q - b * m * r -
+ c * n * p - d * k * r - e * l * p - f * j * q - g * l * n -
+ h * j * o - i * k * m,
+ j * n * r + k * o * p + l * m * q - j * o * q - k * m * r - l * n * p,
};
// Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0.
@@ -195,15 +197,15 @@ double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
int num_roots = SolveCubicPolynomial(P, roots);
// Build the fundamental matrix for each solution.
- for (int kk = 0; kk < num_roots; ++kk) {
+ for (int kk = 0; kk < num_roots; ++kk) {
F->push_back(F1 + roots[kk] * F2);
}
return s;
}
-double FundamentalFromCorrespondences7Point(const Mat &x1,
- const Mat &x2,
- std::vector<Mat3> *F) {
+double FundamentalFromCorrespondences7Point(const Mat& x1,
+ const Mat& x2,
+ std::vector<Mat3>* F) {
DCHECK_EQ(x1.rows(), 2);
DCHECK_GE(x1.cols(), 7);
DCHECK_EQ(x1.rows(), x2.rows());
@@ -218,25 +220,25 @@ double FundamentalFromCorrespondences7Point(const Mat &x1,
ApplyTransformationToPoints(x2, T2, &x2_normalized);
// Estimate the fundamental matrix.
- double smaller_singular_value =
- FundamentalFrom7CorrespondencesLinear(x1_normalized, x2_normalized, &(*F));
+ double smaller_singular_value = FundamentalFrom7CorrespondencesLinear(
+ x1_normalized, x2_normalized, &(*F));
for (int k = 0; k < F->size(); ++k) {
- Mat3 & Fmat = (*F)[k];
+ Mat3& Fmat = (*F)[k];
// Denormalize the fundamental matrix.
Fmat = T2.transpose() * Fmat * T1;
}
return smaller_singular_value;
}
-void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized) {
+void NormalizeFundamental(const Mat3& F, Mat3* F_normalized) {
*F_normalized = F / FrobeniusNorm(F);
if ((*F_normalized)(2, 2) < 0) {
*F_normalized *= -1;
}
}
-double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
+double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2) {
Vec3 x(x1(0), x1(1), 1.0);
Vec3 y(x2(0), x2(1), 1.0);
@@ -244,11 +246,11 @@ double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
Vec3 Ft_y = F.transpose() * y;
double y_F_x = y.dot(F_x);
- return Square(y_F_x) / ( F_x.head<2>().squaredNorm()
- + Ft_y.head<2>().squaredNorm());
+ return Square(y_F_x) /
+ (F_x.head<2>().squaredNorm() + Ft_y.head<2>().squaredNorm());
}
-double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
+double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2) {
Vec3 x(x1(0), x1(1), 1.0);
Vec3 y(x2(0), x2(1), 1.0);
@@ -256,43 +258,40 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
Vec3 Ft_y = F.transpose() * y;
double y_F_x = y.dot(F_x);
- return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm()
- + 1 / Ft_y.head<2>().squaredNorm());
+ return Square(y_F_x) *
+ (1 / F_x.head<2>().squaredNorm() + 1 / Ft_y.head<2>().squaredNorm());
}
// HZ 9.6 pag 257 (formula 9.12)
-void EssentialFromFundamental(const Mat3 &F,
- const Mat3 &K1,
- const Mat3 &K2,
- Mat3 *E) {
+void EssentialFromFundamental(const Mat3& F,
+ const Mat3& K1,
+ const Mat3& K2,
+ Mat3* E) {
*E = K2.transpose() * F * K1;
}
// HZ 9.6 pag 257 (formula 9.12)
// Or http://ai.stanford.edu/~birch/projective/node20.html
-void FundamentalFromEssential(const Mat3 &E,
- const Mat3 &K1,
- const Mat3 &K2,
- Mat3 *F) {
+void FundamentalFromEssential(const Mat3& E,
+ const Mat3& K1,
+ const Mat3& K2,
+ Mat3* F) {
*F = K2.inverse().transpose() * E * K1.inverse();
}
-void RelativeCameraMotion(const Mat3 &R1,
- const Vec3 &t1,
- const Mat3 &R2,
- const Vec3 &t2,
- Mat3 *R,
- Vec3 *t) {
+void RelativeCameraMotion(const Mat3& R1,
+ const Vec3& t1,
+ const Mat3& R2,
+ const Vec3& t2,
+ Mat3* R,
+ Vec3* t) {
*R = R2 * R1.transpose();
*t = t2 - (*R) * t1;
}
// HZ 9.6 pag 257
-void EssentialFromRt(const Mat3 &R1,
- const Vec3 &t1,
- const Mat3 &R2,
- const Vec3 &t2,
- Mat3 *E) {
+void EssentialFromRt(
+ const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E) {
Mat3 R;
Vec3 t;
RelativeCameraMotion(R1, t1, R2, t2, &R, &t);
@@ -301,11 +300,11 @@ void EssentialFromRt(const Mat3 &R1,
}
// HZ 9.6 pag 259 (Result 9.19)
-void MotionFromEssential(const Mat3 &E,
- std::vector<Mat3> *Rs,
- std::vector<Vec3> *ts) {
+void MotionFromEssential(const Mat3& E,
+ std::vector<Mat3>* Rs,
+ std::vector<Vec3>* ts) {
Eigen::JacobiSVD<Mat3> USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
- Mat3 U = USV.matrixU();
+ Mat3 U = USV.matrixU();
Mat3 Vt = USV.matrixV().transpose();
// Last column of U is undetermined since d = (a a 0).
@@ -318,9 +317,11 @@ void MotionFromEssential(const Mat3 &E,
}
Mat3 W;
+ // clang-format off
W << 0, -1, 0,
1, 0, 0,
0, 0, 1;
+ // clang-format on
Mat3 U_W_Vt = U * W * Vt;
Mat3 U_Wt_Vt = U * W.transpose() * Vt;
@@ -332,18 +333,18 @@ void MotionFromEssential(const Mat3 &E,
(*Rs)[3] = U_Wt_Vt;
ts->resize(4);
- (*ts)[0] = U.col(2);
+ (*ts)[0] = U.col(2);
(*ts)[1] = -U.col(2);
- (*ts)[2] = U.col(2);
+ (*ts)[2] = U.col(2);
(*ts)[3] = -U.col(2);
}
-int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
- const std::vector<Vec3> &ts,
- const Mat3 &K1,
- const Vec2 &x1,
- const Mat3 &K2,
- const Vec2 &x2) {
+int MotionFromEssentialChooseSolution(const std::vector<Mat3>& Rs,
+ const std::vector<Vec3>& ts,
+ const Mat3& K1,
+ const Vec2& x1,
+ const Mat3& K2,
+ const Vec2& x2) {
DCHECK_EQ(4, Rs.size());
DCHECK_EQ(4, ts.size());
@@ -354,8 +355,8 @@ int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
t1.setZero();
P_From_KRt(K1, R1, t1, &P1);
for (int i = 0; i < 4; ++i) {
- const Mat3 &R2 = Rs[i];
- const Vec3 &t2 = ts[i];
+ const Mat3& R2 = Rs[i];
+ const Vec3& t2 = ts[i];
P_From_KRt(K2, R2, t2, &P2);
Vec3 X;
TriangulateDLT(P1, x1, P2, x2, &X);
@@ -369,13 +370,13 @@ int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
return -1;
}
-bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
- const Mat3 &K1,
- const Vec2 &x1,
- const Mat3 &K2,
- const Vec2 &x2,
- Mat3 *R,
- Vec3 *t) {
+bool MotionFromEssentialAndCorrespondence(const Mat3& E,
+ const Mat3& K1,
+ const Vec2& x1,
+ const Mat3& K2,
+ const Vec2& x2,
+ Mat3* R,
+ Vec3* t) {
std::vector<Mat3> Rs;
std::vector<Vec3> ts;
MotionFromEssential(E, &Rs, &ts);
@@ -389,7 +390,7 @@ bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
}
}
-void FundamentalToEssential(const Mat3 &F, Mat3 *E) {
+void FundamentalToEssential(const Mat3& F, Mat3* E) {
Eigen::JacobiSVD<Mat3> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV);
// See Hartley & Zisserman page 294, result 11.1, which shows how to get the
@@ -399,8 +400,8 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) {
double s = (a + b) / 2.0;
LG << "Initial reconstruction's rotation is non-euclidean by "
- << (((a - b) / std::max(a, b)) * 100) << "%; singular values:"
- << svd.singularValues().transpose();
+ << (((a - b) / std::max(a, b)) * 100)
+ << "%; singular values:" << svd.singularValues().transpose();
Vec3 diag;
diag << s, s, 0;
@@ -410,9 +411,8 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) {
// Default settings for fundamental estimation which should be suitable
// for a wide range of use cases.
-EstimateFundamentalOptions::EstimateFundamentalOptions(void) :
- max_num_iterations(50),
- expected_average_symmetric_distance(1e-16) {
+EstimateFundamentalOptions::EstimateFundamentalOptions(void)
+ : max_num_iterations(50), expected_average_symmetric_distance(1e-16) {
}
namespace {
@@ -420,12 +420,11 @@ namespace {
// used for fundamental matrix refinement.
class FundamentalSymmetricEpipolarCostFunctor {
public:
- FundamentalSymmetricEpipolarCostFunctor(const Vec2 &x,
- const Vec2 &y)
- : x_(x), y_(y) {}
+ FundamentalSymmetricEpipolarCostFunctor(const Vec2& x, const Vec2& y)
+ : x_(x), y_(y) {}
- template<typename T>
- bool operator()(const T *fundamental_parameters, T *residuals) const {
+ template <typename T>
+ bool operator()(const T* fundamental_parameters, T* residuals) const {
typedef Eigen::Matrix<T, 3, 3> Mat3;
typedef Eigen::Matrix<T, 3, 1> Vec3;
@@ -454,9 +453,10 @@ class FundamentalSymmetricEpipolarCostFunctor {
// average value.
class TerminationCheckingCallback : public ceres::IterationCallback {
public:
- TerminationCheckingCallback(const Mat &x1, const Mat &x2,
- const EstimateFundamentalOptions &options,
- Mat3 *F)
+ TerminationCheckingCallback(const Mat& x1,
+ const Mat& x2,
+ const EstimateFundamentalOptions& options,
+ Mat3* F)
: options_(options), x1_(x1), x2_(x2), F_(F) {}
virtual ceres::CallbackReturnType operator()(
@@ -469,9 +469,7 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
// Calculate average of symmetric epipolar distance.
double average_distance = 0.0;
for (int i = 0; i < x1_.cols(); i++) {
- average_distance = SymmetricEpipolarDistance(*F_,
- x1_.col(i),
- x2_.col(i));
+ average_distance = SymmetricEpipolarDistance(*F_, x1_.col(i), x2_.col(i));
}
average_distance /= x1_.cols();
@@ -483,19 +481,19 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
}
private:
- const EstimateFundamentalOptions &options_;
- const Mat &x1_;
- const Mat &x2_;
- Mat3 *F_;
+ const EstimateFundamentalOptions& options_;
+ const Mat& x1_;
+ const Mat& x2_;
+ Mat3* F_;
};
} // namespace
/* Fundamental transformation estimation. */
bool EstimateFundamentalFromCorrespondences(
- const Mat &x1,
- const Mat &x2,
- const EstimateFundamentalOptions &options,
- Mat3 *F) {
+ const Mat& x1,
+ const Mat& x2,
+ const EstimateFundamentalOptions& options,
+ Mat3* F) {
// Step 1: Algebraic fundamental estimation.
// Assume algebraic estiation always succeeds,
@@ -506,16 +504,15 @@ bool EstimateFundamentalFromCorrespondences(
// Step 2: Refine matrix using Ceres minimizer.
ceres::Problem problem;
for (int i = 0; i < x1.cols(); i++) {
- FundamentalSymmetricEpipolarCostFunctor
- *fundamental_symmetric_epipolar_cost_function =
- new FundamentalSymmetricEpipolarCostFunctor(x1.col(i),
- x2.col(i));
+ FundamentalSymmetricEpipolarCostFunctor*
+ fundamental_symmetric_epipolar_cost_function =
+ new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), x2.col(i));
problem.AddResidualBlock(
- new ceres::AutoDiffCostFunction<
- FundamentalSymmetricEpipolarCostFunctor,
- 2, // num_residuals
- 9>(fundamental_symmetric_epipolar_cost_function),
+ new ceres::AutoDiffCostFunction<FundamentalSymmetricEpipolarCostFunctor,
+ 2, // num_residuals
+ 9>(
+ fundamental_symmetric_epipolar_cost_function),
NULL,
F->data());
}
diff --git a/intern/libmv/libmv/multiview/fundamental.h b/intern/libmv/libmv/multiview/fundamental.h
index a6c7a6802fe..6d25691c4a3 100644
--- a/intern/libmv/libmv/multiview/fundamental.h
+++ b/intern/libmv/libmv/multiview/fundamental.h
@@ -27,36 +27,34 @@
namespace libmv {
-void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2);
-void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F);
+void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2);
+void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F);
/**
* 7 points (minimal case, points coordinates must be normalized before):
*/
-double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- std::vector<Mat3> *F);
+double FundamentalFrom7CorrespondencesLinear(const Mat& x1,
+ const Mat& x2,
+ std::vector<Mat3>* F);
/**
* 7 points (points coordinates must be in image space):
*/
-double FundamentalFromCorrespondences7Point(const Mat &x1,
- const Mat &x2,
- std::vector<Mat3> *F);
+double FundamentalFromCorrespondences7Point(const Mat& x1,
+ const Mat& x2,
+ std::vector<Mat3>* F);
/**
* 8 points (points coordinates must be in image space):
*/
-double NormalizedEightPointSolver(const Mat &x1,
- const Mat &x2,
- Mat3 *F);
+double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F);
/**
* Fundamental matrix utility function:
*/
-void EnforceFundamentalRank2Constraint(Mat3 *F);
+void EnforceFundamentalRank2Constraint(Mat3* F);
-void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized);
+void NormalizeFundamental(const Mat3& F, Mat3* F_normalized);
/**
* Approximate squared reprojection errror.
@@ -64,14 +62,14 @@ void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized);
* See page 287 of HZ equation 11.9. This avoids triangulating the point,
* relying only on the entries in F.
*/
-double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2);
/**
* Calculates the sum of the distances from the points to the epipolar lines.
*
* See page 288 of HZ equation 11.10.
*/
-double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2);
/**
* Compute the relative camera motion between two cameras.
@@ -81,32 +79,29 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
* If T1 and T2 are the camera motions, the computed relative motion is
* T = T2 T1^{-1}
*/
-void RelativeCameraMotion(const Mat3 &R1,
- const Vec3 &t1,
- const Mat3 &R2,
- const Vec3 &t2,
- Mat3 *R,
- Vec3 *t);
-
-void EssentialFromFundamental(const Mat3 &F,
- const Mat3 &K1,
- const Mat3 &K2,
- Mat3 *E);
-
-void FundamentalFromEssential(const Mat3 &E,
- const Mat3 &K1,
- const Mat3 &K2,
- Mat3 *F);
-
-void EssentialFromRt(const Mat3 &R1,
- const Vec3 &t1,
- const Mat3 &R2,
- const Vec3 &t2,
- Mat3 *E);
-
-void MotionFromEssential(const Mat3 &E,
- std::vector<Mat3> *Rs,
- std::vector<Vec3> *ts);
+void RelativeCameraMotion(const Mat3& R1,
+ const Vec3& t1,
+ const Mat3& R2,
+ const Vec3& t2,
+ Mat3* R,
+ Vec3* t);
+
+void EssentialFromFundamental(const Mat3& F,
+ const Mat3& K1,
+ const Mat3& K2,
+ Mat3* E);
+
+void FundamentalFromEssential(const Mat3& E,
+ const Mat3& K1,
+ const Mat3& K2,
+ Mat3* F);
+
+void EssentialFromRt(
+ const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E);
+
+void MotionFromEssential(const Mat3& E,
+ std::vector<Mat3>* Rs,
+ std::vector<Vec3>* ts);
/**
* Choose one of the four possible motion solutions from an essential matrix.
@@ -117,25 +112,25 @@ void MotionFromEssential(const Mat3 &E,
*
* \return index of the right solution or -1 if no solution.
*/
-int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
- const std::vector<Vec3> &ts,
- const Mat3 &K1,
- const Vec2 &x1,
- const Mat3 &K2,
- const Vec2 &x2);
-
-bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
- const Mat3 &K1,
- const Vec2 &x1,
- const Mat3 &K2,
- const Vec2 &x2,
- Mat3 *R,
- Vec3 *t);
+int MotionFromEssentialChooseSolution(const std::vector<Mat3>& Rs,
+ const std::vector<Vec3>& ts,
+ const Mat3& K1,
+ const Vec2& x1,
+ const Mat3& K2,
+ const Vec2& x2);
+
+bool MotionFromEssentialAndCorrespondence(const Mat3& E,
+ const Mat3& K1,
+ const Vec2& x1,
+ const Mat3& K2,
+ const Vec2& x2,
+ Mat3* R,
+ Vec3* t);
/**
* Find closest essential matrix E to fundamental F
*/
-void FundamentalToEssential(const Mat3 &F, Mat3 *E);
+void FundamentalToEssential(const Mat3& F, Mat3* E);
/**
* This structure contains options that controls how the fundamental
@@ -170,10 +165,10 @@ struct EstimateFundamentalOptions {
* refinement.
*/
bool EstimateFundamentalFromCorrespondences(
- const Mat &x1,
- const Mat &x2,
- const EstimateFundamentalOptions &options,
- Mat3 *F);
+ const Mat& x1,
+ const Mat& x2,
+ const EstimateFundamentalOptions& options,
+ Mat3* F);
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/fundamental_test.cc b/intern/libmv/libmv/multiview/fundamental_test.cc
index da0eb449b8f..0ec91ca8d19 100644
--- a/intern/libmv/libmv/multiview/fundamental_test.cc
+++ b/intern/libmv/libmv/multiview/fundamental_test.cc
@@ -34,12 +34,14 @@ using namespace libmv;
TEST(Fundamental, FundamentalFromProjections) {
Mat34 P1_gt, P2_gt;
+ // clang-format off
P1_gt << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0;
P2_gt << 1, 1, 1, 3,
0, 2, 0, 3,
0, 1, 1, 0;
+ // clang-format on
Mat3 F_gt;
FundamentalFromProjections(P1_gt, P2_gt, &F_gt);
@@ -55,8 +57,10 @@ TEST(Fundamental, FundamentalFromProjections) {
TEST(Fundamental, PreconditionerFromPoints) {
int n = 4;
Mat points(2, n);
+ // clang-format off
points << 0, 0, 1, 1,
0, 2, 1, 3;
+ // clang-format on
Mat3 T;
PreconditionerFromPoints(points, &T);
@@ -152,8 +156,8 @@ TEST(Fundamental, MotionFromEssentialAndCorrespondence) {
Mat3 R_estimated;
Vec3 t_estimated;
- MotionFromEssentialAndCorrespondence(E, d.K1, x1, d.K2, x2,
- &R_estimated, &t_estimated);
+ MotionFromEssentialAndCorrespondence(
+ E, d.K1, x1, d.K2, x2, &R_estimated, &t_estimated);
EXPECT_LE(FrobeniusDistance(R_estimated, R), 1e-8);
EXPECT_LE(DistanceL2(t_estimated, t), 1e-8);
diff --git a/intern/libmv/libmv/multiview/homography.cc b/intern/libmv/libmv/multiview/homography.cc
index 69177743f94..2db2c0cd3d5 100644
--- a/intern/libmv/libmv/multiview/homography.cc
+++ b/intern/libmv/libmv/multiview/homography.cc
@@ -26,7 +26,7 @@
#include "libmv/multiview/homography_parameterization.h"
namespace libmv {
-/** 2D Homography transformation estimation in the case that points are in
+/** 2D Homography transformation estimation in the case that points are in
* euclidean coordinates.
*
* x = H y
@@ -44,10 +44,7 @@ namespace libmv {
* (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0|
*/
static bool Homography2DFromCorrespondencesLinearEuc(
- const Mat &x1,
- const Mat &x2,
- Mat3 *H,
- double expected_precision) {
+ const Mat& x1, const Mat& x2, Mat3* H, double expected_precision) {
assert(2 == x1.rows());
assert(4 <= x1.cols());
assert(x1.rows() == x2.rows());
@@ -58,27 +55,27 @@ static bool Homography2DFromCorrespondencesLinearEuc(
Mat b = Mat::Zero(n * 3, 1);
for (int i = 0; i < n; ++i) {
int j = 3 * i;
- L(j, 0) = x1(0, i); // a
- L(j, 1) = x1(1, i); // b
- L(j, 2) = 1.0; // c
+ L(j, 0) = x1(0, i); // a
+ L(j, 1) = x1(1, i); // b
+ L(j, 2) = 1.0; // c
L(j, 6) = -x2(0, i) * x1(0, i); // g
L(j, 7) = -x2(0, i) * x1(1, i); // h
- b(j, 0) = x2(0, i); // i
+ b(j, 0) = x2(0, i); // i
++j;
- L(j, 3) = x1(0, i); // d
- L(j, 4) = x1(1, i); // e
- L(j, 5) = 1.0; // f
+ L(j, 3) = x1(0, i); // d
+ L(j, 4) = x1(1, i); // e
+ L(j, 5) = 1.0; // f
L(j, 6) = -x2(1, i) * x1(0, i); // g
L(j, 7) = -x2(1, i) * x1(1, i); // h
- b(j, 0) = x2(1, i); // i
+ b(j, 0) = x2(1, i); // i
// This ensures better stability
// TODO(julien) make a lite version without this 3rd set
++j;
- L(j, 0) = x2(1, i) * x1(0, i); // a
- L(j, 1) = x2(1, i) * x1(1, i); // b
- L(j, 2) = x2(1, i); // c
+ L(j, 0) = x2(1, i) * x1(0, i); // a
+ L(j, 1) = x2(1, i) * x1(1, i); // b
+ L(j, 2) = x2(1, i); // c
L(j, 3) = -x2(0, i) * x1(0, i); // d
L(j, 4) = -x2(0, i) * x1(1, i); // e
L(j, 5) = -x2(0, i); // f
@@ -86,14 +83,15 @@ static bool Homography2DFromCorrespondencesLinearEuc(
// Solve Lx=B
Vec h = L.fullPivLu().solve(b);
Homography2DNormalizedParameterization<double>::To(h, H);
- if ((L * h).isApprox(b, expected_precision)) {
+ if ((L * h).isApprox(b, expected_precision)) {
return true;
} else {
return false;
}
}
-/** 2D Homography transformation estimation in the case that points are in
+// clang-format off
+/** 2D Homography transformation estimation in the case that points are in
* homogeneous coordinates.
*
* | 0 -x3 x2| |a b c| |y1| -x3*d+x2*g -x3*e+x2*h -x3*f+x2*1 |y1| (-x3*d+x2*g)*y1 (-x3*e+x2*h)*y2 (-x3*f+x2*1)*y3 |0|
@@ -101,13 +99,14 @@ static bool Homography2DFromCorrespondencesLinearEuc(
* |-x2 x1 0| |g h 1| |y3| -x2*a+x1*d -x2*b+x1*e -x2*c+x1*f |y3| (-x2*a+x1*d)*y1 (-x2*b+x1*e)*y2 (-x2*c+x1*f)*y3 |0|
* X = |a b c d e f g h|^t
*/
-bool Homography2DFromCorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- Mat3 *H,
+// clang-format on
+bool Homography2DFromCorrespondencesLinear(const Mat& x1,
+ const Mat& x2,
+ Mat3* H,
double expected_precision) {
if (x1.rows() == 2) {
- return Homography2DFromCorrespondencesLinearEuc(x1, x2, H,
- expected_precision);
+ return Homography2DFromCorrespondencesLinearEuc(
+ x1, x2, H, expected_precision);
}
assert(3 == x1.rows());
assert(4 <= x1.cols());
@@ -122,33 +121,33 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1,
Mat b = Mat::Zero(n * 3, 1);
for (int i = 0; i < n; ++i) {
int j = 3 * i;
- L(j, 0) = x2(w, i) * x1(x, i); // a
- L(j, 1) = x2(w, i) * x1(y, i); // b
- L(j, 2) = x2(w, i) * x1(w, i); // c
+ L(j, 0) = x2(w, i) * x1(x, i); // a
+ L(j, 1) = x2(w, i) * x1(y, i); // b
+ L(j, 2) = x2(w, i) * x1(w, i); // c
L(j, 6) = -x2(x, i) * x1(x, i); // g
L(j, 7) = -x2(x, i) * x1(y, i); // h
- b(j, 0) = x2(x, i) * x1(w, i);
+ b(j, 0) = x2(x, i) * x1(w, i);
++j;
- L(j, 3) = x2(w, i) * x1(x, i); // d
- L(j, 4) = x2(w, i) * x1(y, i); // e
- L(j, 5) = x2(w, i) * x1(w, i); // f
+ L(j, 3) = x2(w, i) * x1(x, i); // d
+ L(j, 4) = x2(w, i) * x1(y, i); // e
+ L(j, 5) = x2(w, i) * x1(w, i); // f
L(j, 6) = -x2(y, i) * x1(x, i); // g
L(j, 7) = -x2(y, i) * x1(y, i); // h
- b(j, 0) = x2(y, i) * x1(w, i);
+ b(j, 0) = x2(y, i) * x1(w, i);
// This ensures better stability
++j;
- L(j, 0) = x2(y, i) * x1(x, i); // a
- L(j, 1) = x2(y, i) * x1(y, i); // b
- L(j, 2) = x2(y, i) * x1(w, i); // c
+ L(j, 0) = x2(y, i) * x1(x, i); // a
+ L(j, 1) = x2(y, i) * x1(y, i); // b
+ L(j, 2) = x2(y, i) * x1(w, i); // c
L(j, 3) = -x2(x, i) * x1(x, i); // d
L(j, 4) = -x2(x, i) * x1(y, i); // e
L(j, 5) = -x2(x, i) * x1(w, i); // f
}
// Solve Lx=B
Vec h = L.fullPivLu().solve(b);
- if ((L * h).isApprox(b, expected_precision)) {
+ if ((L * h).isApprox(b, expected_precision)) {
Homography2DNormalizedParameterization<double>::To(h, H);
return true;
} else {
@@ -158,32 +157,30 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1,
// Default settings for homography estimation which should be suitable
// for a wide range of use cases.
-EstimateHomographyOptions::EstimateHomographyOptions(void) :
- use_normalization(true),
- max_num_iterations(50),
- expected_average_symmetric_distance(1e-16) {
+EstimateHomographyOptions::EstimateHomographyOptions(void)
+ : use_normalization(true),
+ max_num_iterations(50),
+ expected_average_symmetric_distance(1e-16) {
}
namespace {
-void GetNormalizedPoints(const Mat &original_points,
- Mat *normalized_points,
- Mat3 *normalization_matrix) {
+void GetNormalizedPoints(const Mat& original_points,
+ Mat* normalized_points,
+ Mat3* normalization_matrix) {
IsotropicPreconditionerFromPoints(original_points, normalization_matrix);
- ApplyTransformationToPoints(original_points,
- *normalization_matrix,
- normalized_points);
+ ApplyTransformationToPoints(
+ original_points, *normalization_matrix, normalized_points);
}
// Cost functor which computes symmetric geometric distance
// used for homography matrix refinement.
class HomographySymmetricGeometricCostFunctor {
public:
- HomographySymmetricGeometricCostFunctor(const Vec2 &x,
- const Vec2 &y)
- : x_(x), y_(y) { }
+ HomographySymmetricGeometricCostFunctor(const Vec2& x, const Vec2& y)
+ : x_(x), y_(y) {}
- template<typename T>
- bool operator()(const T *homography_parameters, T *residuals) const {
+ template <typename T>
+ bool operator()(const T* homography_parameters, T* residuals) const {
typedef Eigen::Matrix<T, 3, 3> Mat3;
typedef Eigen::Matrix<T, 3, 1> Vec3;
@@ -221,9 +218,10 @@ class HomographySymmetricGeometricCostFunctor {
// average value.
class TerminationCheckingCallback : public ceres::IterationCallback {
public:
- TerminationCheckingCallback(const Mat &x1, const Mat &x2,
- const EstimateHomographyOptions &options,
- Mat3 *H)
+ TerminationCheckingCallback(const Mat& x1,
+ const Mat& x2,
+ const EstimateHomographyOptions& options,
+ Mat3* H)
: options_(options), x1_(x1), x2_(x2), H_(H) {}
virtual ceres::CallbackReturnType operator()(
@@ -236,9 +234,8 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
// Calculate average of symmetric geometric distance.
double average_distance = 0.0;
for (int i = 0; i < x1_.cols(); i++) {
- average_distance = SymmetricGeometricDistance(*H_,
- x1_.col(i),
- x2_.col(i));
+ average_distance =
+ SymmetricGeometricDistance(*H_, x1_.col(i), x2_.col(i));
}
average_distance /= x1_.cols();
@@ -250,10 +247,10 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
}
private:
- const EstimateHomographyOptions &options_;
- const Mat &x1_;
- const Mat &x2_;
- Mat3 *H_;
+ const EstimateHomographyOptions& options_;
+ const Mat& x1_;
+ const Mat& x2_;
+ Mat3* H_;
};
} // namespace
@@ -261,10 +258,10 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
* euclidean coordinates.
*/
bool EstimateHomography2DFromCorrespondences(
- const Mat &x1,
- const Mat &x2,
- const EstimateHomographyOptions &options,
- Mat3 *H) {
+ const Mat& x1,
+ const Mat& x2,
+ const EstimateHomographyOptions& options,
+ Mat3* H) {
// TODO(sergey): Support homogenous coordinates, not just euclidean.
assert(2 == x1.rows());
@@ -272,8 +269,7 @@ bool EstimateHomography2DFromCorrespondences(
assert(x1.rows() == x2.rows());
assert(x1.cols() == x2.cols());
- Mat3 T1 = Mat3::Identity(),
- T2 = Mat3::Identity();
+ Mat3 T1 = Mat3::Identity(), T2 = Mat3::Identity();
// Step 1: Algebraic homography estimation.
Mat x1_normalized, x2_normalized;
@@ -300,16 +296,15 @@ bool EstimateHomography2DFromCorrespondences(
// Step 2: Refine matrix using Ceres minimizer.
ceres::Problem problem;
for (int i = 0; i < x1.cols(); i++) {
- HomographySymmetricGeometricCostFunctor
- *homography_symmetric_geometric_cost_function =
- new HomographySymmetricGeometricCostFunctor(x1.col(i),
- x2.col(i));
+ HomographySymmetricGeometricCostFunctor*
+ homography_symmetric_geometric_cost_function =
+ new HomographySymmetricGeometricCostFunctor(x1.col(i), x2.col(i));
problem.AddResidualBlock(
- new ceres::AutoDiffCostFunction<
- HomographySymmetricGeometricCostFunctor,
- 4, // num_residuals
- 9>(homography_symmetric_geometric_cost_function),
+ new ceres::AutoDiffCostFunction<HomographySymmetricGeometricCostFunctor,
+ 4, // num_residuals
+ 9>(
+ homography_symmetric_geometric_cost_function),
NULL,
H->data());
}
@@ -335,15 +330,16 @@ bool EstimateHomography2DFromCorrespondences(
return summary.IsSolutionUsable();
}
+// clang-format off
/**
* x2 ~ A * x1
* x2^t * Hi * A *x1 = 0
- * H1 = H2 = H3 =
+ * H1 = H2 = H3 =
* | 0 0 0 1| |-x2w| |0 0 0 0| | 0 | | 0 0 1 0| |-x2z|
* | 0 0 0 0| -> | 0 | |0 0 1 0| -> |-x2z| | 0 0 0 0| -> | 0 |
* | 0 0 0 0| | 0 | |0-1 0 0| | x2y| |-1 0 0 0| | x2x|
* |-1 0 0 0| | x2x| |0 0 0 0| | 0 | | 0 0 0 0| | 0 |
- * H4 = H5 = H6 =
+ * H4 = H5 = H6 =
* |0 0 0 0| | 0 | | 0 1 0 0| |-x2y| |0 0 0 0| | 0 |
* |0 0 0 1| -> |-x2w| |-1 0 0 0| -> | x2x| |0 0 0 0| -> | 0 |
* |0 0 0 0| | 0 | | 0 0 0 0| | 0 | |0 0 0 1| |-x2w|
@@ -361,10 +357,11 @@ bool EstimateHomography2DFromCorrespondences(
* x2^t * H6 * A *x1 = (-x2w*i +x2z*m )*x1x + (-x2w*j +x2z*n )*x1y + (-x2w*k +x2z*o )*x1z + (-x2w*l +x2z*1 )*x1w = 0
*
* X = |a b c d e f g h i j k l m n o|^t
-*/
-bool Homography3DFromCorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- Mat4 *H,
+ */
+// clang-format on
+bool Homography3DFromCorrespondencesLinear(const Mat& x1,
+ const Mat& x2,
+ Mat4* H,
double expected_precision) {
assert(4 == x1.rows());
assert(5 <= x1.cols());
@@ -379,68 +376,68 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1,
Mat b = Mat::Zero(n * 6, 1);
for (int i = 0; i < n; ++i) {
int j = 6 * i;
- L(j, 0) = -x2(w, i) * x1(x, i); // a
- L(j, 1) = -x2(w, i) * x1(y, i); // b
- L(j, 2) = -x2(w, i) * x1(z, i); // c
- L(j, 3) = -x2(w, i) * x1(w, i); // d
- L(j, 12) = x2(x, i) * x1(x, i); // m
- L(j, 13) = x2(x, i) * x1(y, i); // n
- L(j, 14) = x2(x, i) * x1(z, i); // o
- b(j, 0) = -x2(x, i) * x1(w, i);
+ L(j, 0) = -x2(w, i) * x1(x, i); // a
+ L(j, 1) = -x2(w, i) * x1(y, i); // b
+ L(j, 2) = -x2(w, i) * x1(z, i); // c
+ L(j, 3) = -x2(w, i) * x1(w, i); // d
+ L(j, 12) = x2(x, i) * x1(x, i); // m
+ L(j, 13) = x2(x, i) * x1(y, i); // n
+ L(j, 14) = x2(x, i) * x1(z, i); // o
+ b(j, 0) = -x2(x, i) * x1(w, i);
++j;
- L(j, 4) = -x2(z, i) * x1(x, i); // e
- L(j, 5) = -x2(z, i) * x1(y, i); // f
- L(j, 6) = -x2(z, i) * x1(z, i); // g
- L(j, 7) = -x2(z, i) * x1(w, i); // h
- L(j, 8) = x2(y, i) * x1(x, i); // i
- L(j, 9) = x2(y, i) * x1(y, i); // j
- L(j, 10) = x2(y, i) * x1(z, i); // k
- L(j, 11) = x2(y, i) * x1(w, i); // l
+ L(j, 4) = -x2(z, i) * x1(x, i); // e
+ L(j, 5) = -x2(z, i) * x1(y, i); // f
+ L(j, 6) = -x2(z, i) * x1(z, i); // g
+ L(j, 7) = -x2(z, i) * x1(w, i); // h
+ L(j, 8) = x2(y, i) * x1(x, i); // i
+ L(j, 9) = x2(y, i) * x1(y, i); // j
+ L(j, 10) = x2(y, i) * x1(z, i); // k
+ L(j, 11) = x2(y, i) * x1(w, i); // l
++j;
- L(j, 0) = -x2(z, i) * x1(x, i); // a
- L(j, 1) = -x2(z, i) * x1(y, i); // b
- L(j, 2) = -x2(z, i) * x1(z, i); // c
- L(j, 3) = -x2(z, i) * x1(w, i); // d
- L(j, 8) = x2(x, i) * x1(x, i); // i
- L(j, 9) = x2(x, i) * x1(y, i); // j
- L(j, 10) = x2(x, i) * x1(z, i); // k
- L(j, 11) = x2(x, i) * x1(w, i); // l
+ L(j, 0) = -x2(z, i) * x1(x, i); // a
+ L(j, 1) = -x2(z, i) * x1(y, i); // b
+ L(j, 2) = -x2(z, i) * x1(z, i); // c
+ L(j, 3) = -x2(z, i) * x1(w, i); // d
+ L(j, 8) = x2(x, i) * x1(x, i); // i
+ L(j, 9) = x2(x, i) * x1(y, i); // j
+ L(j, 10) = x2(x, i) * x1(z, i); // k
+ L(j, 11) = x2(x, i) * x1(w, i); // l
++j;
- L(j, 4) = -x2(w, i) * x1(x, i); // e
- L(j, 5) = -x2(w, i) * x1(y, i); // f
- L(j, 6) = -x2(w, i) * x1(z, i); // g
- L(j, 7) = -x2(w, i) * x1(w, i); // h
- L(j, 12) = x2(y, i) * x1(x, i); // m
- L(j, 13) = x2(y, i) * x1(y, i); // n
- L(j, 14) = x2(y, i) * x1(z, i); // o
- b(j, 0) = -x2(y, i) * x1(w, i);
+ L(j, 4) = -x2(w, i) * x1(x, i); // e
+ L(j, 5) = -x2(w, i) * x1(y, i); // f
+ L(j, 6) = -x2(w, i) * x1(z, i); // g
+ L(j, 7) = -x2(w, i) * x1(w, i); // h
+ L(j, 12) = x2(y, i) * x1(x, i); // m
+ L(j, 13) = x2(y, i) * x1(y, i); // n
+ L(j, 14) = x2(y, i) * x1(z, i); // o
+ b(j, 0) = -x2(y, i) * x1(w, i);
++j;
L(j, 0) = -x2(y, i) * x1(x, i); // a
L(j, 1) = -x2(y, i) * x1(y, i); // b
L(j, 2) = -x2(y, i) * x1(z, i); // c
L(j, 3) = -x2(y, i) * x1(w, i); // d
- L(j, 4) = x2(x, i) * x1(x, i); // e
- L(j, 5) = x2(x, i) * x1(y, i); // f
- L(j, 6) = x2(x, i) * x1(z, i); // g
- L(j, 7) = x2(x, i) * x1(w, i); // h
+ L(j, 4) = x2(x, i) * x1(x, i); // e
+ L(j, 5) = x2(x, i) * x1(y, i); // f
+ L(j, 6) = x2(x, i) * x1(z, i); // g
+ L(j, 7) = x2(x, i) * x1(w, i); // h
++j;
- L(j, 8) = -x2(w, i) * x1(x, i); // i
- L(j, 9) = -x2(w, i) * x1(y, i); // j
+ L(j, 8) = -x2(w, i) * x1(x, i); // i
+ L(j, 9) = -x2(w, i) * x1(y, i); // j
L(j, 10) = -x2(w, i) * x1(z, i); // k
L(j, 11) = -x2(w, i) * x1(w, i); // l
- L(j, 12) = x2(z, i) * x1(x, i); // m
- L(j, 13) = x2(z, i) * x1(y, i); // n
- L(j, 14) = x2(z, i) * x1(z, i); // o
- b(j, 0) = -x2(z, i) * x1(w, i);
+ L(j, 12) = x2(z, i) * x1(x, i); // m
+ L(j, 13) = x2(z, i) * x1(y, i); // n
+ L(j, 14) = x2(z, i) * x1(z, i); // o
+ b(j, 0) = -x2(z, i) * x1(w, i);
}
// Solve Lx=B
Vec h = L.fullPivLu().solve(b);
- if ((L * h).isApprox(b, expected_precision)) {
+ if ((L * h).isApprox(b, expected_precision)) {
Homography3DNormalizedParameterization<double>::To(h, H);
return true;
} else {
@@ -448,9 +445,9 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1,
}
}
-double SymmetricGeometricDistance(const Mat3 &H,
- const Vec2 &x1,
- const Vec2 &x2) {
+double SymmetricGeometricDistance(const Mat3& H,
+ const Vec2& x1,
+ const Vec2& x2) {
Vec3 x(x1(0), x1(1), 1.0);
Vec3 y(x2(0), x2(1), 1.0);
diff --git a/intern/libmv/libmv/multiview/homography.h b/intern/libmv/libmv/multiview/homography.h
index a76aa9405a5..0742c6f7c70 100644
--- a/intern/libmv/libmv/multiview/homography.h
+++ b/intern/libmv/libmv/multiview/homography.h
@@ -49,11 +49,11 @@ namespace libmv {
* \return True if the transformation estimation has succeeded.
* \note There must be at least 4 non-colinear points.
*/
-bool Homography2DFromCorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- Mat3 *H,
- double expected_precision =
- EigenDouble::dummy_precision());
+bool Homography2DFromCorrespondencesLinear(
+ const Mat& x1,
+ const Mat& x2,
+ Mat3* H,
+ double expected_precision = EigenDouble::dummy_precision());
/**
* This structure contains options that controls how the homography
@@ -101,10 +101,10 @@ struct EstimateHomographyOptions {
* refinement.
*/
bool EstimateHomography2DFromCorrespondences(
- const Mat &x1,
- const Mat &x2,
- const EstimateHomographyOptions &options,
- Mat3 *H);
+ const Mat& x1,
+ const Mat& x2,
+ const EstimateHomographyOptions& options,
+ Mat3* H);
/**
* 3D Homography transformation estimation.
@@ -129,20 +129,20 @@ bool EstimateHomography2DFromCorrespondences(
* \note Need at least 5 non coplanar points
* \note Points coordinates must be in homogeneous coordinates
*/
-bool Homography3DFromCorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- Mat4 *H,
- double expected_precision =
- EigenDouble::dummy_precision());
+bool Homography3DFromCorrespondencesLinear(
+ const Mat& x1,
+ const Mat& x2,
+ Mat4* H,
+ double expected_precision = EigenDouble::dummy_precision());
/**
* Calculate symmetric geometric cost:
*
* D(H * x1, x2)^2 + D(H^-1 * x2, x1)
*/
-double SymmetricGeometricDistance(const Mat3 &H,
- const Vec2 &x1,
- const Vec2 &x2);
+double SymmetricGeometricDistance(const Mat3& H,
+ const Vec2& x1,
+ const Vec2& x2);
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/homography_error.h b/intern/libmv/libmv/multiview/homography_error.h
index f8b9d45e73c..786ca245ea6 100644
--- a/intern/libmv/libmv/multiview/homography_error.h
+++ b/intern/libmv/libmv/multiview/homography_error.h
@@ -27,18 +27,18 @@ namespace libmv {
namespace homography {
namespace homography2D {
- /**
- * Structure for estimating the asymmetric error between a vector x2 and the
- * transformed x1 such that
- * Error = ||x2 - Psi(H * x1)||^2
- * where Psi is the function that transforms homogeneous to euclidean coords.
- * \note It should be distributed as Chi-squared with k = 2.
- */
+/**
+ * Structure for estimating the asymmetric error between a vector x2 and the
+ * transformed x1 such that
+ * Error = ||x2 - Psi(H * x1)||^2
+ * where Psi is the function that transforms homogeneous to euclidean coords.
+ * \note It should be distributed as Chi-squared with k = 2.
+ */
struct AsymmetricError {
/**
- * Computes the asymmetric residuals between a set of 2D points x2 and the
+ * Computes the asymmetric residuals between a set of 2D points x2 and the
* transformed 2D point set x1 such that
- * Residuals_i = x2_i - Psi(H * x1_i)
+ * Residuals_i = x2_i - Psi(H * x1_i)
* where Psi is the function that transforms homogeneous to euclidean coords.
*
* \param[in] H The 3x3 homography matrix.
@@ -47,8 +47,7 @@ struct AsymmetricError {
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
* \param[out] dx A 2xN matrix of column vectors of residuals errors
*/
- static void Residuals(const Mat &H, const Mat &x1,
- const Mat &x2, Mat2X *dx) {
+ static void Residuals(const Mat& H, const Mat& x1, const Mat& x2, Mat2X* dx) {
dx->resize(2, x1.cols());
Mat3X x2h_est;
if (x1.rows() == 2)
@@ -63,19 +62,18 @@ struct AsymmetricError {
*dx = HomogeneousToEuclidean(static_cast<Mat3X>(x2)) - *dx;
}
/**
- * Computes the asymmetric residuals between a 2D point x2 and the transformed
+ * Computes the asymmetric residuals between a 2D point x2 and the transformed
* 2D point x1 such that
- * Residuals = x2 - Psi(H * x1)
+ * Residuals = x2 - Psi(H * x1)
* where Psi is the function that transforms homogeneous to euclidean coords.
*
* \param[in] H The 3x3 homography matrix.
* The estimated homography should approximatelly hold the condition y = H x.
- * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
- * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
* \param[out] dx A vector of size 2 of the residual error
*/
- static void Residuals(const Mat &H, const Vec &x1,
- const Vec &x2, Vec2 *dx) {
+ static void Residuals(const Mat& H, const Vec& x1, const Vec& x2, Vec2* dx) {
Vec3 x2h_est;
if (x1.rows() == 2)
x2h_est = H * EuclideanToHomogeneous(static_cast<Vec2>(x1));
@@ -85,10 +83,10 @@ struct AsymmetricError {
*dx = x2 - x2h_est.head<2>() / x2h_est[2];
else
*dx = HomogeneousToEuclidean(static_cast<Vec3>(x2)) -
- x2h_est.head<2>() / x2h_est[2];
+ x2h_est.head<2>() / x2h_est[2];
}
/**
- * Computes the squared norm of the residuals between a set of 2D points x2
+ * Computes the squared norm of the residuals between a set of 2D points x2
* and the transformed 2D point set x1 such that
* Error = || x2 - Psi(H * x1) ||^2
* where Psi is the function that transforms homogeneous to euclidean coords.
@@ -99,70 +97,70 @@ struct AsymmetricError {
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
* \return The squared norm of the asymmetric residuals errors
*/
- static double Error(const Mat &H, const Mat &x1, const Mat &x2) {
+ static double Error(const Mat& H, const Mat& x1, const Mat& x2) {
Mat2X dx;
Residuals(H, x1, x2, &dx);
return dx.squaredNorm();
}
/**
- * Computes the squared norm of the residuals between a 2D point x2 and the
- * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2
+ * Computes the squared norm of the residuals between a 2D point x2 and the
+ * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2
* where Psi is the function that transforms homogeneous to euclidean coords.
*
* \param[in] H The 3x3 homography matrix.
* The estimated homography should approximatelly hold the condition y = H x.
- * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
- * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
* \return The squared norm of the asymmetric residual error
*/
- static double Error(const Mat &H, const Vec &x1, const Vec &x2) {
+ static double Error(const Mat& H, const Vec& x1, const Vec& x2) {
Vec2 dx;
Residuals(H, x1, x2, &dx);
return dx.squaredNorm();
}
};
- /**
- * Structure for estimating the symmetric error
- * between a vector x2 and the transformed x1 such that
- * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2
- * where Psi is the function that transforms homogeneous to euclidean coords.
- * \note It should be distributed as Chi-squared with k = 4.
- */
+/**
+ * Structure for estimating the symmetric error
+ * between a vector x2 and the transformed x1 such that
+ * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2
+ * where Psi is the function that transforms homogeneous to euclidean coords.
+ * \note It should be distributed as Chi-squared with k = 4.
+ */
struct SymmetricError {
/**
- * Computes the squared norm of the residuals between x2 and the
- * transformed x1 such that
+ * Computes the squared norm of the residuals between x2 and the
+ * transformed x1 such that
* Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2
* where Psi is the function that transforms homogeneous to euclidean coords.
*
* \param[in] H The 3x3 homography matrix.
* The estimated homography should approximatelly hold the condition y = H x.
- * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
- * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
* \return The squared norm of the symmetric residuals errors
*/
- static double Error(const Mat &H, const Vec &x1, const Vec &x2) {
+ static double Error(const Mat& H, const Vec& x1, const Vec& x2) {
// TODO(keir): This is awesomely inefficient because it does a 3x3
// inversion for each evaluation.
Mat3 Hinv = H.inverse();
- return AsymmetricError::Error(H, x1, x2) +
+ return AsymmetricError::Error(H, x1, x2) +
AsymmetricError::Error(Hinv, x2, x1);
}
// TODO(julien) Add residuals function \see AsymmetricError
};
- /**
- * Structure for estimating the algebraic error (cross product)
- * between a vector x2 and the transformed x1 such that
- * Error = ||[x2] * H * x1||^^2
- * where [x2] is the skew matrix of x2.
- */
+/**
+ * Structure for estimating the algebraic error (cross product)
+ * between a vector x2 and the transformed x1 such that
+ * Error = ||[x2] * H * x1||^^2
+ * where [x2] is the skew matrix of x2.
+ */
struct AlgebraicError {
// TODO(julien) Make an AlgebraicError2Rows and AlgebraicError3Rows
/**
- * Computes the algebraic residuals (cross product) between a set of 2D
- * points x2 and the transformed 2D point set x1 such that
+ * Computes the algebraic residuals (cross product) between a set of 2D
+ * points x2 and the transformed 2D point set x1 such that
* [x2] * H * x1 where [x2] is the skew matrix of x2.
*
* \param[in] H The 3x3 homography matrix.
@@ -171,8 +169,7 @@ struct AlgebraicError {
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
* \param[out] dx A 3xN matrix of column vectors of residuals errors
*/
- static void Residuals(const Mat &H, const Mat &x1,
- const Mat &x2, Mat3X *dx) {
+ static void Residuals(const Mat& H, const Mat& x1, const Mat& x2, Mat3X* dx) {
dx->resize(3, x1.cols());
Vec3 col;
for (int i = 0; i < x1.cols(); ++i) {
@@ -181,18 +178,17 @@ struct AlgebraicError {
}
}
/**
- * Computes the algebraic residuals (cross product) between a 2D point x2
- * and the transformed 2D point x1 such that
+ * Computes the algebraic residuals (cross product) between a 2D point x2
+ * and the transformed 2D point x1 such that
* [x2] * H * x1 where [x2] is the skew matrix of x2.
*
* \param[in] H The 3x3 homography matrix.
* The estimated homography should approximatelly hold the condition y = H x.
- * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
- * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
* \param[out] dx A vector of size 3 of the residual error
*/
- static void Residuals(const Mat &H, const Vec &x1,
- const Vec &x2, Vec3 *dx) {
+ static void Residuals(const Mat& H, const Vec& x1, const Vec& x2, Vec3* dx) {
Vec3 x2h_est;
if (x1.rows() == 2)
x2h_est = H * EuclideanToHomogeneous(static_cast<Vec2>(x1));
@@ -206,8 +202,8 @@ struct AlgebraicError {
// identical 3x3 skew matrix for each evaluation.
}
/**
- * Computes the squared norm of the algebraic residuals between a set of 2D
- * points x2 and the transformed 2D point set x1 such that
+ * Computes the squared norm of the algebraic residuals between a set of 2D
+ * points x2 and the transformed 2D point set x1 such that
* [x2] * H * x1 where [x2] is the skew matrix of x2.
*
* \param[in] H The 3x3 homography matrix.
@@ -216,23 +212,23 @@ struct AlgebraicError {
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
* \return The squared norm of the asymmetric residuals errors
*/
- static double Error(const Mat &H, const Mat &x1, const Mat &x2) {
+ static double Error(const Mat& H, const Mat& x1, const Mat& x2) {
Mat3X dx;
Residuals(H, x1, x2, &dx);
return dx.squaredNorm();
}
/**
- * Computes the squared norm of the algebraic residuals between a 2D point x2
- * and the transformed 2D point x1 such that
+ * Computes the squared norm of the algebraic residuals between a 2D point x2
+ * and the transformed 2D point x1 such that
* [x2] * H * x1 where [x2] is the skew matrix of x2.
*
* \param[in] H The 3x3 homography matrix.
* The estimated homography should approximatelly hold the condition y = H x.
- * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
- * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
+ * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
* \return The squared norm of the asymmetric residual error
*/
- static double Error(const Mat &H, const Vec &x1, const Vec &x2) {
+ static double Error(const Mat& H, const Vec& x1, const Vec& x2) {
Vec3 dx;
Residuals(H, x1, x2, &dx);
return dx.squaredNorm();
diff --git a/intern/libmv/libmv/multiview/homography_parameterization.h b/intern/libmv/libmv/multiview/homography_parameterization.h
index ca8fbd8066e..ae2d74da9ff 100644
--- a/intern/libmv/libmv/multiview/homography_parameterization.h
+++ b/intern/libmv/libmv/multiview/homography_parameterization.h
@@ -25,64 +25,72 @@
namespace libmv {
-/** A parameterization of the 2D homography matrix that uses 8 parameters so
+/** A parameterization of the 2D homography matrix that uses 8 parameters so
* that the matrix is normalized (H(2,2) == 1).
* The homography matrix H is built from a list of 8 parameters (a, b,...g, h)
* as follows
- * |a b c|
+ * |a b c|
* H = |d e f|
- * |g h 1|
+ * |g h 1|
*/
-template<typename T = double>
+template <typename T = double>
class Homography2DNormalizedParameterization {
public:
typedef Eigen::Matrix<T, 8, 1> Parameters; // a, b, ... g, h
typedef Eigen::Matrix<T, 3, 3> Parameterized; // H
/// Convert from the 8 parameters to a H matrix.
- static void To(const Parameters &p, Parameterized *h) {
+ static void To(const Parameters& p, Parameterized* h) {
+ // clang-format off
*h << p(0), p(1), p(2),
p(3), p(4), p(5),
p(6), p(7), 1.0;
+ // clang-format on
}
/// Convert from a H matrix to the 8 parameters.
- static void From(const Parameterized &h, Parameters *p) {
+ static void From(const Parameterized& h, Parameters* p) {
+ // clang-format off
*p << h(0, 0), h(0, 1), h(0, 2),
h(1, 0), h(1, 1), h(1, 2),
h(2, 0), h(2, 1);
+ // clang-format on
}
};
-/** A parameterization of the 2D homography matrix that uses 15 parameters so
+/** A parameterization of the 2D homography matrix that uses 15 parameters so
* that the matrix is normalized (H(3,3) == 1).
* The homography matrix H is built from a list of 15 parameters (a, b,...n, o)
* as follows
- * |a b c d|
+ * |a b c d|
* H = |e f g h|
* |i j k l|
- * |m n o 1|
+ * |m n o 1|
*/
-template<typename T = double>
+template <typename T = double>
class Homography3DNormalizedParameterization {
public:
- typedef Eigen::Matrix<T, 15, 1> Parameters; // a, b, ... n, o
- typedef Eigen::Matrix<T, 4, 4> Parameterized; // H
+ typedef Eigen::Matrix<T, 15, 1> Parameters; // a, b, ... n, o
+ typedef Eigen::Matrix<T, 4, 4> Parameterized; // H
/// Convert from the 15 parameters to a H matrix.
- static void To(const Parameters &p, Parameterized *h) {
+ static void To(const Parameters& p, Parameterized* h) {
+ // clang-format off
*h << p(0), p(1), p(2), p(3),
p(4), p(5), p(6), p(7),
p(8), p(9), p(10), p(11),
p(12), p(13), p(14), 1.0;
+ // clang-format on
}
/// Convert from a H matrix to the 15 parameters.
- static void From(const Parameterized &h, Parameters *p) {
+ static void From(const Parameterized& h, Parameters* p) {
+ // clang-format off
*p << h(0, 0), h(0, 1), h(0, 2), h(0, 3),
h(1, 0), h(1, 1), h(1, 2), h(1, 3),
h(2, 0), h(2, 1), h(2, 2), h(2, 3),
h(3, 0), h(3, 1), h(3, 2);
+ // clang-format on
}
};
diff --git a/intern/libmv/libmv/multiview/homography_test.cc b/intern/libmv/libmv/multiview/homography_test.cc
index 8d7266e3d11..87d1c85028d 100644
--- a/intern/libmv/libmv/multiview/homography_test.cc
+++ b/intern/libmv/libmv/multiview/homography_test.cc
@@ -18,10 +18,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "testing/testing.h"
+#include "libmv/multiview/homography.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/projection.h"
-#include "libmv/multiview/homography.h"
+#include "testing/testing.h"
namespace {
using namespace libmv;
@@ -34,9 +34,7 @@ namespace {
// TODO(sergey): Consider using this in all tests since possible homography
// matrix is not fixed to a single value and different-looking matrices
// might actually crrespond to the same exact transform.
-void CheckHomography2DTransform(const Mat3 &H,
- const Mat &x1,
- const Mat &x2) {
+void CheckHomography2DTransform(const Mat3& H, const Mat& x1, const Mat& x2) {
for (int i = 0; i < x2.cols(); ++i) {
Vec3 x2_expected = x2.col(i);
Vec3 x2_observed = H * x1.col(i);
@@ -49,15 +47,19 @@ void CheckHomography2DTransform(const Mat3 &H,
TEST(Homography2DTest, Rotation45AndTranslationXY) {
Mat x1(3, 4);
+ // clang-format off
x1 << 0, 1, 0, 5,
0, 0, 2, 3,
1, 1, 1, 1;
+ // clang-format on
double angle = 45.0;
Mat3 m;
+ // clang-format off
m << cos(angle), -sin(angle), -2,
sin(angle), cos(angle), 5,
0, 0, 1;
+ // clang-format on
Mat x2 = x1;
// Transform point from ground truth matrix
@@ -76,13 +78,17 @@ TEST(Homography2DTest, Rotation45AndTranslationXY) {
TEST(Homography2DTest, AffineGeneral4) {
// TODO(julien) find why it doesn't work with 4 points!!!
Mat x1(3, 4);
+ // clang-format off
x1 << 0, 1, 0, 2,
0, 0, 1, 2,
1, 1, 1, 1;
+ // clang-format on
Mat3 m;
+ // clang-format off
m << 3, -1, 4,
6, -2, -3,
0, 0, 1;
+ // clang-format on
Mat x2 = x1;
for (int i = 0; i < x2.cols(); ++i) {
@@ -109,13 +115,17 @@ TEST(Homography2DTest, AffineGeneral4) {
TEST(Homography2DTest, AffineGeneral5) {
Mat x1(3, 5);
+ // clang-format off
x1 << 0, 1, 0, 2, 5,
0, 0, 1, 2, 2,
1, 1, 1, 1, 1;
+ // clang-format on
Mat3 m;
+ // clang-format off
m << 3, -1, 4,
6, -2, -3,
0, 0, 1;
+ // clang-format on
Mat x2 = x1;
for (int i = 0; i < x2.cols(); ++i)
@@ -142,13 +152,17 @@ TEST(Homography2DTest, AffineGeneral5) {
TEST(Homography2DTest, HomographyGeneral) {
Mat x1(3, 4);
+ // clang-format off
x1 << 0, 1, 0, 5,
0, 0, 2, 3,
1, 1, 1, 1;
+ // clang-format on
Mat3 m;
+ // clang-format off
m << 3, -1, 4,
6, -2, -3,
1, -3, 1;
+ // clang-format on
Mat x2 = x1;
for (int i = 0; i < x2.cols(); ++i)
@@ -164,10 +178,12 @@ TEST(Homography2DTest, HomographyGeneral) {
TEST(Homography3DTest, RotationAndTranslationXYZ) {
Mat x1(4, 5);
+ // clang-format off
x1 << 0, 0, 1, 5, 2,
0, 1, 2, 3, 5,
0, 2, 0, 1, 5,
1, 1, 1, 1, 1;
+ // clang-format on
Mat4 M;
M.setIdentity();
/*
@@ -178,24 +194,30 @@ TEST(Homography3DTest, RotationAndTranslationXYZ) {
// Rotation on x + translation
double angle = 45.0;
Mat4 rot;
+ // clang-format off
rot << 1, 0, 0, 1,
0, cos(angle), -sin(angle), 3,
0, sin(angle), cos(angle), -2,
0, 0, 0, 1;
+ // clang-format on
M *= rot;
// Rotation on y
angle = 25.0;
+ // clang-format off
rot << cos(angle), 0, sin(angle), 0,
0, 1, 0, 0,
-sin(angle), 0, cos(angle), 0,
0, 0, 0, 1;
+ // clang-format on
M *= rot;
// Rotation on z
angle = 5.0;
+ // clang-format off
rot << cos(angle), -sin(angle), 0, 0,
sin(angle), cos(angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
+ // clang-format on
M *= rot;
Mat x2 = x1;
for (int i = 0; i < x2.cols(); ++i) {
@@ -212,15 +234,19 @@ TEST(Homography3DTest, RotationAndTranslationXYZ) {
TEST(Homography3DTest, AffineGeneral) {
Mat x1(4, 5);
+ // clang-format off
x1 << 0, 0, 1, 5, 2,
0, 1, 2, 3, 5,
0, 2, 0, 1, 5,
1, 1, 1, 1, 1;
+ // clang-format on
Mat4 m;
+ // clang-format off
m << 3, -1, 4, 1,
6, -2, -3, -6,
1, 0, 1, 2,
0, 0, 0, 1;
+ // clang-format on
Mat x2 = x1;
for (int i = 0; i < x2.cols(); ++i) {
@@ -236,15 +262,19 @@ TEST(Homography3DTest, AffineGeneral) {
TEST(Homography3DTest, HomographyGeneral) {
Mat x1(4, 5);
+ // clang-format off
x1 << 0, 0, 1, 5, 2,
0, 1, 2, 3, 5,
0, 2, 0, 1, 5,
1, 1, 1, 1, 1;
+ // clang-format on
Mat4 m;
+ // clang-format off
m << 3, -1, 4, 1,
6, -2, -3, -6,
1, 0, 1, 2,
-3, 1, 0, 1;
+ // clang-format on
Mat x2 = x1;
for (int i = 0; i < x2.cols(); ++i) {
diff --git a/intern/libmv/libmv/multiview/nviewtriangulation.h b/intern/libmv/libmv/multiview/nviewtriangulation.h
index f4614ab1a5c..b2a320953a7 100644
--- a/intern/libmv/libmv/multiview/nviewtriangulation.h
+++ b/intern/libmv/libmv/multiview/nviewtriangulation.h
@@ -34,22 +34,22 @@ namespace libmv {
// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The
// output, X, is a homogeneous four vectors.
-template<typename T>
-void NViewTriangulate(const Matrix<T, 2, Dynamic> &x,
- const vector<Matrix<T, 3, 4> > &Ps,
- Matrix<T, 4, 1> *X) {
+template <typename T>
+void NViewTriangulate(const Matrix<T, 2, Dynamic>& x,
+ const vector<Matrix<T, 3, 4>>& Ps,
+ Matrix<T, 4, 1>* X) {
int nviews = x.cols();
assert(nviews == Ps.size());
- Matrix<T, Dynamic, Dynamic> design(3*nviews, 4 + nviews);
+ Matrix<T, Dynamic, Dynamic> design(3 * nviews, 4 + nviews);
design.setConstant(0.0);
for (int i = 0; i < nviews; i++) {
- design.template block<3, 4>(3*i, 0) = -Ps[i];
- design(3*i + 0, 4 + i) = x(0, i);
- design(3*i + 1, 4 + i) = x(1, i);
- design(3*i + 2, 4 + i) = 1.0;
+ design.template block<3, 4>(3 * i, 0) = -Ps[i];
+ design(3 * i + 0, 4 + i) = x(0, i);
+ design(3 * i + 1, 4 + i) = x(1, i);
+ design(3 * i + 2, 4 + i) = 1.0;
}
- Matrix<T, Dynamic, 1> X_and_alphas;
+ Matrix<T, Dynamic, 1> X_and_alphas;
Nullspace(&design, &X_and_alphas);
X->resize(4);
*X = X_and_alphas.head(4);
@@ -60,16 +60,16 @@ void NViewTriangulate(const Matrix<T, 2, Dynamic> &x,
// This method uses the algebraic distance approximation.
// Note that this method works better when the 2D points are normalized
// with an isotopic normalization.
-template<typename T>
-void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic> &x,
- const vector<Matrix<T, 3, 4> > &Ps,
- Matrix<T, 4, 1> *X) {
+template <typename T>
+void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic>& x,
+ const vector<Matrix<T, 3, 4>>& Ps,
+ Matrix<T, 4, 1>* X) {
int nviews = x.cols();
assert(nviews == Ps.size());
- Matrix<T, Dynamic, 4> design(2*nviews, 4);
+ Matrix<T, Dynamic, 4> design(2 * nviews, 4);
for (int i = 0; i < nviews; i++) {
- design.template block<2, 4>(2*i, 0) = SkewMatMinimal(x.col(i)) * Ps[i];
+ design.template block<2, 4>(2 * i, 0) = SkewMatMinimal(x.col(i)) * Ps[i];
}
X->resize(4);
Nullspace(&design, X);
diff --git a/intern/libmv/libmv/multiview/nviewtriangulation_test.cc b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc
index 5a4d8499753..dba5fd07d5c 100644
--- a/intern/libmv/libmv/multiview/nviewtriangulation_test.cc
+++ b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc
@@ -54,7 +54,7 @@ TEST(NViewTriangulate, FiveViews) {
// Check reprojection error. Should be nearly zero.
for (int j = 0; j < nviews; ++j) {
- Vec3 x_reprojected = Ps[j]*X;
+ Vec3 x_reprojected = Ps[j] * X;
x_reprojected /= x_reprojected(2);
double error = (x_reprojected.head(2) - xs.col(j)).norm();
EXPECT_NEAR(error, 0.0, 1e-9);
@@ -84,7 +84,7 @@ TEST(NViewTriangulateAlgebraic, FiveViews) {
// Check reprojection error. Should be nearly zero.
for (int j = 0; j < nviews; ++j) {
- Vec3 x_reprojected = Ps[j]*X;
+ Vec3 x_reprojected = Ps[j] * X;
x_reprojected /= x_reprojected(2);
double error = (x_reprojected.head<2>() - xs.col(j)).norm();
EXPECT_NEAR(error, 0.0, 1e-9);
diff --git a/intern/libmv/libmv/multiview/panography.cc b/intern/libmv/libmv/multiview/panography.cc
index b62802948c4..42b1c19d65e 100644
--- a/intern/libmv/libmv/multiview/panography.cc
+++ b/intern/libmv/libmv/multiview/panography.cc
@@ -24,8 +24,9 @@
namespace libmv {
static bool Build_Minimal2Point_PolynomialFactor(
- const Mat & x1, const Mat & x2,
- double * P) { // P must be a double[4]
+ const Mat& x1,
+ const Mat& x2,
+ double* P) { // P must be a double[4]
assert(2 == x1.rows());
assert(2 == x1.cols());
assert(x1.rows() == x2.rows());
@@ -40,11 +41,11 @@ static bool Build_Minimal2Point_PolynomialFactor(
Vec yx2 = (x2.col(1)).transpose();
double b12 = xx2.dot(yx2);
- double a1 = xx1.squaredNorm();
- double a2 = yx1.squaredNorm();
+ double a1 = xx1.squaredNorm();
+ double a2 = yx1.squaredNorm();
- double b1 = xx2.squaredNorm();
- double b2 = yx2.squaredNorm();
+ double b1 = xx2.squaredNorm();
+ double b2 = yx2.squaredNorm();
// Build the 3rd degre polynomial in F^2.
//
@@ -52,10 +53,12 @@ static bool Build_Minimal2Point_PolynomialFactor(
//
// Coefficients in ascending powers of alpha, i.e. P[N]*x^N.
// Run panography_coeffs.py to get the below coefficients.
- P[0] = b1*b2*a12*a12-a1*a2*b12*b12;
- P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12;
- P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12;
- P[3] = b1+b2-2*b12-a1-a2+2*a12;
+ P[0] = b1 * b2 * a12 * a12 - a1 * a2 * b12 * b12;
+ P[1] = -2 * a1 * a2 * b12 + 2 * a12 * b1 * b2 + b1 * a12 * a12 +
+ b2 * a12 * a12 - a1 * b12 * b12 - a2 * b12 * b12;
+ P[2] = b1 * b2 - a1 * a2 - 2 * a1 * b12 - 2 * a2 * b12 + 2 * a12 * b1 +
+ 2 * a12 * b2 + a12 * a12 - b12 * b12;
+ P[3] = b1 + b2 - 2 * b12 - a1 - a2 + 2 * a12;
// If P[3] equal to 0 we get ill conditionned data
return (P[3] != 0.0);
@@ -67,8 +70,9 @@ static bool Build_Minimal2Point_PolynomialFactor(
//
// [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic
// Stitching. CVPR07.
-void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
- vector<double> *fs) {
+void F_FromCorrespondance_2points(const Mat& x1,
+ const Mat& x2,
+ vector<double>* fs) {
// Build Polynomial factor to get squared focal value.
double P[4];
Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]);
@@ -79,8 +83,8 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
//
double roots[3];
int num_roots = SolveCubicPolynomial(P, roots);
- for (int i = 0; i < num_roots; ++i) {
- if (roots[i] > 0.0) {
+ for (int i = 0; i < num_roots; ++i) {
+ if (roots[i] > 0.0) {
fs->push_back(sqrt(roots[i]));
}
}
@@ -92,17 +96,18 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
// K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point
// sets. IEEE Transactions on Pattern Analysis and Machine Intelligence,
// 9:698-700, 1987.
-void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2,
+void GetR_FixedCameraCenter(const Mat& x1,
+ const Mat& x2,
const double focal,
- Mat3 *R) {
+ Mat3* R) {
assert(3 == x1.rows());
assert(2 <= x1.cols());
assert(x1.rows() == x2.rows());
assert(x1.cols() == x2.cols());
// Build simplified K matrix
- Mat3 K(Mat3::Identity() * 1.0/focal);
- K(2, 2)= 1.0;
+ Mat3 K(Mat3::Identity() * 1.0 / focal);
+ K(2, 2) = 1.0;
// Build the correlation matrix; equation (22) in [1].
Mat3 C = Mat3::Zero();
@@ -115,9 +120,9 @@ void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2,
// Solve for rotation. Equations (24) and (25) in [1].
Eigen::JacobiSVD<Mat> svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV);
Mat3 scale = Mat3::Identity();
- scale(2, 2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0)
- ? 1.0
- : -1.0;
+ scale(2, 2) =
+ ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) ? 1.0
+ : -1.0;
(*R) = svd.matrixU() * scale * svd.matrixV().transpose();
}
diff --git a/intern/libmv/libmv/multiview/panography.h b/intern/libmv/libmv/multiview/panography.h
index 6e87bd71304..5860a34d1fd 100644
--- a/intern/libmv/libmv/multiview/panography.h
+++ b/intern/libmv/libmv/multiview/panography.h
@@ -22,9 +22,9 @@
#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H
#define LIBMV_MULTIVIEW_PANOGRAPHY_H
+#include "libmv/base/vector.h"
#include "libmv/numeric/numeric.h"
#include "libmv/numeric/poly.h"
-#include "libmv/base/vector.h"
namespace libmv {
@@ -53,8 +53,9 @@ namespace libmv {
// K = [0 f 0]
// [0 0 1]
//
-void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
- vector<double> *fs);
+void F_FromCorrespondance_2points(const Mat& x1,
+ const Mat& x2,
+ vector<double>* fs);
// Compute the 3x3 rotation matrix that fits two 3D point clouds in the least
// square sense. The method is from:
@@ -90,9 +91,10 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
//
// R = arg min || X2 - R * x1 ||
//
-void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2,
+void GetR_FixedCameraCenter(const Mat& x1,
+ const Mat& x2,
const double focal,
- Mat3 *R);
+ Mat3* R);
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/panography_kernel.cc b/intern/libmv/libmv/multiview/panography_kernel.cc
index 8fdc9e79aed..e8ba648e352 100644
--- a/intern/libmv/libmv/multiview/panography_kernel.cc
+++ b/intern/libmv/libmv/multiview/panography_kernel.cc
@@ -25,7 +25,7 @@ namespace libmv {
namespace panography {
namespace kernel {
-void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs) {
+void TwoPointSolver::Solve(const Mat& x1, const Mat& x2, vector<Mat3>* Hs) {
// Solve for the focal lengths.
vector<double> fs;
F_FromCorrespondance_2points(x1, x2, &fs);
@@ -34,7 +34,7 @@ void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs) {
Mat x1h, x2h;
EuclideanToHomogeneous(x1, &x1h);
EuclideanToHomogeneous(x2, &x2h);
- for (int i = 0; i < fs.size(); ++i) {
+ for (int i = 0; i < fs.size(); ++i) {
Mat3 K1 = Mat3::Identity() * fs[i];
K1(2, 2) = 1.0;
diff --git a/intern/libmv/libmv/multiview/panography_kernel.h b/intern/libmv/libmv/multiview/panography_kernel.h
index a6adbd54b20..d50d3ea0789 100644
--- a/intern/libmv/libmv/multiview/panography_kernel.h
+++ b/intern/libmv/libmv/multiview/panography_kernel.h
@@ -23,9 +23,9 @@
#include "libmv/base/vector.h"
#include "libmv/multiview/conditioning.h"
+#include "libmv/multiview/homography_error.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/two_view_kernel.h"
-#include "libmv/multiview/homography_error.h"
#include "libmv/numeric/numeric.h"
namespace libmv {
@@ -34,18 +34,18 @@ namespace kernel {
struct TwoPointSolver {
enum { MINIMUM_SAMPLES = 2 };
- static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs);
+ static void Solve(const Mat& x1, const Mat& x2, vector<Mat3>* Hs);
};
-typedef two_view::kernel::Kernel<
- TwoPointSolver, homography::homography2D::AsymmetricError, Mat3>
- UnnormalizedKernel;
+typedef two_view::kernel::
+ Kernel<TwoPointSolver, homography::homography2D::AsymmetricError, Mat3>
+ UnnormalizedKernel;
typedef two_view::kernel::Kernel<
- two_view::kernel::NormalizedSolver<TwoPointSolver, UnnormalizerI>,
- homography::homography2D::AsymmetricError,
- Mat3>
- Kernel;
+ two_view::kernel::NormalizedSolver<TwoPointSolver, UnnormalizerI>,
+ homography::homography2D::AsymmetricError,
+ Mat3>
+ Kernel;
} // namespace kernel
} // namespace panography
diff --git a/intern/libmv/libmv/multiview/panography_test.cc b/intern/libmv/libmv/multiview/panography_test.cc
index 96d52acfc3c..a7cbd371d40 100644
--- a/intern/libmv/libmv/multiview/panography_test.cc
+++ b/intern/libmv/libmv/multiview/panography_test.cc
@@ -18,8 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "libmv/logging/logging.h"
#include "libmv/multiview/panography.h"
+#include "libmv/logging/logging.h"
#include "libmv/multiview/panography_kernel.h"
#include "libmv/multiview/projection.h"
#include "libmv/numeric/numeric.h"
@@ -30,18 +30,16 @@ namespace {
TEST(Panography, PrintSomeSharedFocalEstimationValues) {
Mat x1(2, 2), x2(2, 2);
- x1<< 158, 78,
- 124, 113;
- x2<< 300, 214,
- 125, 114;
+ x1 << 158, 78, 124, 113;
+ x2 << 300, 214, 125, 114;
// Normalize data (set principal point 0,0 and image border to 1.0).
x1.block<1, 2>(0, 0) /= 320;
x1.block<1, 2>(1, 0) /= 240;
x2.block<1, 2>(0, 0) /= 320;
x2.block<1, 2>(1, 0) /= 240;
- x1+=Mat2::Constant(0.5);
- x2+=Mat2::Constant(0.5);
+ x1 += Mat2::Constant(0.5);
+ x2 += Mat2::Constant(0.5);
vector<double> fs;
F_FromCorrespondance_2points(x1, x2, &fs);
@@ -53,9 +51,11 @@ TEST(Panography, PrintSomeSharedFocalEstimationValues) {
TEST(Panography, GetR_FixedCameraCenterWithIdentity) {
Mat x1(3, 3);
+ // clang-format off
x1 << 0.5, 0.6, 0.7,
0.5, 0.5, 0.4,
10.0, 10.0, 10.0;
+ // clang-format on
Mat3 R;
GetR_FixedCameraCenter(x1, x1, 1.0, &R);
@@ -68,16 +68,20 @@ TEST(Panography, Homography_GetR_Test_PitchY30) {
int n = 3;
Mat x1(3, n);
+ // clang-format off
x1 << 0.5, 0.6, 0.7,
0.5, 0.5, 0.4,
10, 10, 10;
+ // clang-format on
Mat x2 = x1;
const double alpha = 30.0 * M_PI / 180.0;
Mat3 rotY;
+ // clang-format off
rotY << cos(alpha), 0, -sin(alpha),
0, 1, 0,
sin(alpha), 0, cos(alpha);
+ // clang-format on
for (int i = 0; i < n; ++i) {
x2.block<3, 1>(0, i) = rotY * x1.col(i);
@@ -101,17 +105,23 @@ TEST(Panography, Homography_GetR_Test_PitchY30) {
TEST(MinimalPanoramic, Real_Case_Kernel) {
const int n = 2;
Mat x1(2, n); // From image 0.jpg
+ // clang-format off
x1<< 158, 78,
124, 113;
+ // clang-format on
Mat x2(2, n); // From image 3.jpg
+ // clang-format off
x2<< 300, 214,
125, 114;
+ // clang-format on
Mat3 Ground_TruthHomography;
+ // clang-format off
Ground_TruthHomography<< 1, 0.02, 129.83,
-0.02, 1.012, 0.07823,
0, 0, 1;
+ // clang-format on
vector<Mat3> Hs;
@@ -130,7 +140,7 @@ TEST(MinimalPanoramic, Real_Case_Kernel) {
// Assert that residuals are small enough
for (int i = 0; i < n; ++i) {
Vec x1p = H * x1h.col(i);
- Vec residuals = x1p/x1p(2) - x2h.col(i);
+ Vec residuals = x1p / x1p(2) - x2h.col(i);
EXPECT_MATRIX_NEAR_ZERO(residuals, 1e-5);
}
}
diff --git a/intern/libmv/libmv/multiview/projection.cc b/intern/libmv/libmv/multiview/projection.cc
index f8bece3de68..001da89e127 100644
--- a/intern/libmv/libmv/multiview/projection.cc
+++ b/intern/libmv/libmv/multiview/projection.cc
@@ -23,13 +23,13 @@
namespace libmv {
-void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P) {
+void P_From_KRt(const Mat3& K, const Mat3& R, const Vec3& t, Mat34* P) {
P->block<3, 3>(0, 0) = R;
P->col(3) = t;
(*P) = K * (*P);
}
-void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
+void KRt_From_P(const Mat34& P, Mat3* Kp, Mat3* Rp, Vec3* tp) {
// Decompose using the RQ decomposition HZ A4.1.1 pag.579.
Mat3 K = P.block(0, 0, 3, 3);
@@ -44,9 +44,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
c /= l;
s /= l;
Mat3 Qx;
+ // clang-format off
Qx << 1, 0, 0,
0, c, -s,
0, s, c;
+ // clang-format on
K = K * Qx;
Q = Qx.transpose() * Q;
}
@@ -58,9 +60,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
c /= l;
s /= l;
Mat3 Qy;
+ // clang-format off
Qy << c, 0, s,
0, 1, 0,
-s, 0, c;
+ // clang-format on
K = K * Qy;
Q = Qy.transpose() * Q;
}
@@ -72,9 +76,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
c /= l;
s /= l;
Mat3 Qz;
+ // clang-format off
Qz << c, -s, 0,
s, c, 0,
0, 0, 1;
+ // clang-format on
K = K * Qz;
Q = Qz.transpose() * Q;
}
@@ -92,17 +98,21 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
}
if (K(1, 1) < 0) {
Mat3 S;
+ // clang-format off
S << 1, 0, 0,
0, -1, 0,
0, 0, 1;
+ // clang-format on
K = K * S;
R = S * R;
}
if (K(0, 0) < 0) {
Mat3 S;
+ // clang-format off
S << -1, 0, 0,
0, 1, 0,
0, 0, 1;
+ // clang-format on
K = K * S;
R = S * R;
}
@@ -122,26 +132,30 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
*tp = t;
}
-void ProjectionShiftPrincipalPoint(const Mat34 &P,
- const Vec2 &principal_point,
- const Vec2 &principal_point_new,
- Mat34 *P_new) {
+void ProjectionShiftPrincipalPoint(const Mat34& P,
+ const Vec2& principal_point,
+ const Vec2& principal_point_new,
+ Mat34* P_new) {
Mat3 T;
+ // clang-format off
T << 1, 0, principal_point_new(0) - principal_point(0),
0, 1, principal_point_new(1) - principal_point(1),
0, 0, 1;
+ // clang-format on
*P_new = T * P;
}
-void ProjectionChangeAspectRatio(const Mat34 &P,
- const Vec2 &principal_point,
+void ProjectionChangeAspectRatio(const Mat34& P,
+ const Vec2& principal_point,
double aspect_ratio,
double aspect_ratio_new,
- Mat34 *P_new) {
+ Mat34* P_new) {
Mat3 T;
+ // clang-format off
T << 1, 0, 0,
0, aspect_ratio_new / aspect_ratio, 0,
0, 0, 1;
+ // clang-format on
Mat34 P_temp;
ProjectionShiftPrincipalPoint(P, principal_point, Vec2(0, 0), &P_temp);
@@ -149,7 +163,7 @@ void ProjectionChangeAspectRatio(const Mat34 &P,
ProjectionShiftPrincipalPoint(P_temp, Vec2(0, 0), principal_point, P_new);
}
-void HomogeneousToEuclidean(const Mat &H, Mat *X) {
+void HomogeneousToEuclidean(const Mat& H, Mat* X) {
int d = H.rows() - 1;
int n = H.cols();
X->resize(d, n);
@@ -161,29 +175,29 @@ void HomogeneousToEuclidean(const Mat &H, Mat *X) {
}
}
-void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e) {
+void HomogeneousToEuclidean(const Mat3X& h, Mat2X* e) {
e->resize(2, h.cols());
e->row(0) = h.row(0).array() / h.row(2).array();
e->row(1) = h.row(1).array() / h.row(2).array();
}
-void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e) {
+void HomogeneousToEuclidean(const Mat4X& h, Mat3X* e) {
e->resize(3, h.cols());
e->row(0) = h.row(0).array() / h.row(3).array();
e->row(1) = h.row(1).array() / h.row(3).array();
e->row(2) = h.row(2).array() / h.row(3).array();
}
-void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X) {
+void HomogeneousToEuclidean(const Vec3& H, Vec2* X) {
double w = H(2);
*X << H(0) / w, H(1) / w;
}
-void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X) {
+void HomogeneousToEuclidean(const Vec4& H, Vec3* X) {
double w = H(3);
*X << H(0) / w, H(1) / w, H(2) / w;
}
-void EuclideanToHomogeneous(const Mat &X, Mat *H) {
+void EuclideanToHomogeneous(const Mat& X, Mat* H) {
int d = X.rows();
int n = X.cols();
H->resize(d + 1, n);
@@ -191,32 +205,32 @@ void EuclideanToHomogeneous(const Mat &X, Mat *H) {
H->row(d).setOnes();
}
-void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H) {
+void EuclideanToHomogeneous(const Vec2& X, Vec3* H) {
*H << X(0), X(1), 1;
}
-void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H) {
+void EuclideanToHomogeneous(const Vec3& X, Vec4* H) {
*H << X(0), X(1), X(2), 1;
}
// TODO(julien) Call conditioning.h/ApplyTransformationToPoints ?
-void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n) {
+void EuclideanToNormalizedCamera(const Mat2X& x, const Mat3& K, Mat2X* n) {
Mat3X x_image_h;
EuclideanToHomogeneous(x, &x_image_h);
Mat3X x_camera_h = K.inverse() * x_image_h;
HomogeneousToEuclidean(x_camera_h, n);
}
-void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n) {
+void HomogeneousToNormalizedCamera(const Mat3X& x, const Mat3& K, Mat2X* n) {
Mat3X x_camera_h = K.inverse() * x;
HomogeneousToEuclidean(x_camera_h, n);
}
-double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X) {
- return (R*X)(2) + t(2);
+double Depth(const Mat3& R, const Vec3& t, const Vec3& X) {
+ return (R * X)(2) + t(2);
}
-double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X) {
+double Depth(const Mat3& R, const Vec3& t, const Vec4& X) {
Vec3 Xe = X.head<3>() / X(3);
return Depth(R, t, Xe);
}
diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h
index 8f304f31ec6..ba8fc5d8303 100644
--- a/intern/libmv/libmv/multiview/projection.h
+++ b/intern/libmv/libmv/multiview/projection.h
@@ -25,108 +25,108 @@
namespace libmv {
-void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P);
-void KRt_From_P(const Mat34 &P, Mat3 *K, Mat3 *R, Vec3 *t);
+void P_From_KRt(const Mat3& K, const Mat3& R, const Vec3& t, Mat34* P);
+void KRt_From_P(const Mat34& P, Mat3* K, Mat3* R, Vec3* t);
// Applies a change of basis to the image coordinates of the projection matrix
// so that the principal point becomes principal_point_new.
-void ProjectionShiftPrincipalPoint(const Mat34 &P,
- const Vec2 &principal_point,
- const Vec2 &principal_point_new,
- Mat34 *P_new);
+void ProjectionShiftPrincipalPoint(const Mat34& P,
+ const Vec2& principal_point,
+ const Vec2& principal_point_new,
+ Mat34* P_new);
// Applies a change of basis to the image coordinates of the projection matrix
// so that the aspect ratio becomes aspect_ratio_new. This is done by
// stretching the y axis. The aspect ratio is defined as the quotient between
// the focal length of the y and the x axis.
-void ProjectionChangeAspectRatio(const Mat34 &P,
- const Vec2 &principal_point,
+void ProjectionChangeAspectRatio(const Mat34& P,
+ const Vec2& principal_point,
double aspect_ratio,
double aspect_ratio_new,
- Mat34 *P_new);
-
-void HomogeneousToEuclidean(const Mat &H, Mat *X);
-void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e);
-void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e);
-void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X);
-void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X);
-inline Vec2 HomogeneousToEuclidean(const Vec3 &h) {
+ Mat34* P_new);
+
+void HomogeneousToEuclidean(const Mat& H, Mat* X);
+void HomogeneousToEuclidean(const Mat3X& h, Mat2X* e);
+void HomogeneousToEuclidean(const Mat4X& h, Mat3X* e);
+void HomogeneousToEuclidean(const Vec3& H, Vec2* X);
+void HomogeneousToEuclidean(const Vec4& H, Vec3* X);
+inline Vec2 HomogeneousToEuclidean(const Vec3& h) {
return h.head<2>() / h(2);
}
-inline Vec3 HomogeneousToEuclidean(const Vec4 &h) {
+inline Vec3 HomogeneousToEuclidean(const Vec4& h) {
return h.head<3>() / h(3);
}
-inline Mat2X HomogeneousToEuclidean(const Mat3X &h) {
+inline Mat2X HomogeneousToEuclidean(const Mat3X& h) {
Mat2X e(2, h.cols());
e.row(0) = h.row(0).array() / h.row(2).array();
e.row(1) = h.row(1).array() / h.row(2).array();
return e;
}
-void EuclideanToHomogeneous(const Mat &X, Mat *H);
-inline Mat3X EuclideanToHomogeneous(const Mat2X &x) {
+void EuclideanToHomogeneous(const Mat& X, Mat* H);
+inline Mat3X EuclideanToHomogeneous(const Mat2X& x) {
Mat3X h(3, x.cols());
h.block(0, 0, 2, x.cols()) = x;
h.row(2).setOnes();
return h;
}
-inline void EuclideanToHomogeneous(const Mat2X &x, Mat3X *h) {
+inline void EuclideanToHomogeneous(const Mat2X& x, Mat3X* h) {
h->resize(3, x.cols());
h->block(0, 0, 2, x.cols()) = x;
h->row(2).setOnes();
}
-inline Mat4X EuclideanToHomogeneous(const Mat3X &x) {
+inline Mat4X EuclideanToHomogeneous(const Mat3X& x) {
Mat4X h(4, x.cols());
h.block(0, 0, 3, x.cols()) = x;
h.row(3).setOnes();
return h;
}
-inline void EuclideanToHomogeneous(const Mat3X &x, Mat4X *h) {
+inline void EuclideanToHomogeneous(const Mat3X& x, Mat4X* h) {
h->resize(4, x.cols());
h->block(0, 0, 3, x.cols()) = x;
h->row(3).setOnes();
}
-void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H);
-void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H);
-inline Vec3 EuclideanToHomogeneous(const Vec2 &x) {
+void EuclideanToHomogeneous(const Vec2& X, Vec3* H);
+void EuclideanToHomogeneous(const Vec3& X, Vec4* H);
+inline Vec3 EuclideanToHomogeneous(const Vec2& x) {
return Vec3(x(0), x(1), 1);
}
-inline Vec4 EuclideanToHomogeneous(const Vec3 &x) {
+inline Vec4 EuclideanToHomogeneous(const Vec3& x) {
return Vec4(x(0), x(1), x(2), 1);
}
// Conversion from image coordinates to normalized camera coordinates
-void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n);
-void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n);
+void EuclideanToNormalizedCamera(const Mat2X& x, const Mat3& K, Mat2X* n);
+void HomogeneousToNormalizedCamera(const Mat3X& x, const Mat3& K, Mat2X* n);
-inline Vec2 Project(const Mat34 &P, const Vec3 &X) {
+inline Vec2 Project(const Mat34& P, const Vec3& X) {
Vec4 HX;
HX << X, 1.0;
Vec3 hx = P * HX;
return hx.head<2>() / hx(2);
}
-inline void Project(const Mat34 &P, const Vec4 &X, Vec3 *x) {
+inline void Project(const Mat34& P, const Vec4& X, Vec3* x) {
*x = P * X;
}
-inline void Project(const Mat34 &P, const Vec4 &X, Vec2 *x) {
+inline void Project(const Mat34& P, const Vec4& X, Vec2* x) {
Vec3 hx = P * X;
*x = hx.head<2>() / hx(2);
}
-inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) {
+inline void Project(const Mat34& P, const Vec3& X, Vec3* x) {
Vec4 HX;
HX << X, 1.0;
Project(P, HX, x);
}
-inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) {
+inline void Project(const Mat34& P, const Vec3& X, Vec2* x) {
Vec3 hx;
Project(P, X, &hx);
*x = hx.head<2>() / hx(2);
}
-inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) {
+inline void Project(const Mat34& P, const Mat4X& X, Mat2X* x) {
x->resize(2, X.cols());
for (int c = 0; c < X.cols(); ++c) {
Vec3 hx = P * X.col(c);
@@ -134,13 +134,13 @@ inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) {
}
}
-inline Mat2X Project(const Mat34 &P, const Mat4X &X) {
+inline Mat2X Project(const Mat34& P, const Mat4X& X) {
Mat2X x;
Project(P, X, &x);
return x;
}
-inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) {
+inline void Project(const Mat34& P, const Mat3X& X, Mat2X* x) {
x->resize(2, X.cols());
for (int c = 0; c < X.cols(); ++c) {
Vec4 HX;
@@ -150,7 +150,7 @@ inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) {
}
}
-inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) {
+inline void Project(const Mat34& P, const Mat3X& X, const Vecu& ids, Mat2X* x) {
x->resize(2, ids.size());
Vec4 HX;
Vec3 hx;
@@ -161,26 +161,26 @@ inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) {
}
}
-inline Mat2X Project(const Mat34 &P, const Mat3X &X) {
+inline Mat2X Project(const Mat34& P, const Mat3X& X) {
Mat2X x(2, X.cols());
Project(P, X, &x);
return x;
}
-inline Mat2X Project(const Mat34 &P, const Mat3X &X, const Vecu &ids) {
+inline Mat2X Project(const Mat34& P, const Mat3X& X, const Vecu& ids) {
Mat2X x(2, ids.size());
Project(P, X, ids, &x);
return x;
}
-double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X);
-double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X);
+double Depth(const Mat3& R, const Vec3& t, const Vec3& X);
+double Depth(const Mat3& R, const Vec3& t, const Vec4& X);
/**
-* Returns true if the homogenious 3D point X is in front of
-* the camera P.
-*/
-inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) {
+ * Returns true if the homogenious 3D point X is in front of
+ * the camera P.
+ */
+inline bool isInFrontOfCamera(const Mat34& P, const Vec4& X) {
double condition_1 = P.row(2).dot(X) * X[3];
double condition_2 = X[2] * X[3];
if (condition_1 > 0 && condition_2 > 0)
@@ -189,37 +189,37 @@ inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) {
return false;
}
-inline bool isInFrontOfCamera(const Mat34 &P, const Vec3 &X) {
+inline bool isInFrontOfCamera(const Mat34& P, const Vec3& X) {
Vec4 X_homo;
X_homo.segment<3>(0) = X;
X_homo(3) = 1;
- return isInFrontOfCamera( P, X_homo);
+ return isInFrontOfCamera(P, X_homo);
}
/**
-* Transforms a 2D point from pixel image coordinates to a 2D point in
-* normalized image coordinates.
-*/
-inline Vec2 ImageToNormImageCoordinates(Mat3 &Kinverse, Vec2 &x) {
- Vec3 x_h = Kinverse*EuclideanToHomogeneous(x);
- return HomogeneousToEuclidean( x_h );
+ * Transforms a 2D point from pixel image coordinates to a 2D point in
+ * normalized image coordinates.
+ */
+inline Vec2 ImageToNormImageCoordinates(Mat3& Kinverse, Vec2& x) {
+ Vec3 x_h = Kinverse * EuclideanToHomogeneous(x);
+ return HomogeneousToEuclidean(x_h);
}
/// Estimates the root mean square error (2D)
-inline double RootMeanSquareError(const Mat2X &x_image,
- const Mat4X &X_world,
- const Mat34 &P) {
+inline double RootMeanSquareError(const Mat2X& x_image,
+ const Mat4X& X_world,
+ const Mat34& P) {
size_t num_points = x_image.cols();
Mat2X dx = Project(P, X_world) - x_image;
return dx.norm() / num_points;
}
/// Estimates the root mean square error (2D)
-inline double RootMeanSquareError(const Mat2X &x_image,
- const Mat3X &X_world,
- const Mat3 &K,
- const Mat3 &R,
- const Vec3 &t) {
+inline double RootMeanSquareError(const Mat2X& x_image,
+ const Mat3X& X_world,
+ const Mat3& K,
+ const Mat3& R,
+ const Vec3& t) {
Mat34 P;
P_From_KRt(K, R, t, &P);
size_t num_points = x_image.cols();
diff --git a/intern/libmv/libmv/multiview/projection_test.cc b/intern/libmv/libmv/multiview/projection_test.cc
index 40e766bfae7..683edefa99c 100644
--- a/intern/libmv/libmv/multiview/projection_test.cc
+++ b/intern/libmv/libmv/multiview/projection_test.cc
@@ -29,14 +29,18 @@ using namespace libmv;
TEST(Projection, P_From_KRt) {
Mat3 K, Kp;
+ // clang-format off
K << 10, 1, 30,
0, 20, 40,
0, 0, 1;
+ // clang-format on
Mat3 R, Rp;
+ // clang-format off
R << 1, 0, 0,
0, 1, 0,
0, 0, 1;
+ // clang-format on
Vec3 t, tp;
t << 1, 2, 3;
@@ -62,16 +66,18 @@ Vec4 GetRandomPoint() {
TEST(Projection, isInFrontOfCamera) {
Mat34 P;
+ // clang-format off
P << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0;
+ // clang-format on
Vec4 X_front = GetRandomPoint();
Vec4 X_back = GetRandomPoint();
- X_front(2) = 10; /* Any point in the positive Z direction
- * where Z > 1 is in front of the camera. */
- X_back(2) = -10; /* Any point in the negative Z direction
- * is behind the camera. */
+ X_front(2) = 10; /* Any point in the positive Z direction
+ * where Z > 1 is in front of the camera. */
+ X_back(2) = -10; /* Any point in the negative Z direction
+ * is behind the camera. */
bool res_front = isInFrontOfCamera(P, X_front);
bool res_back = isInFrontOfCamera(P, X_back);
@@ -82,12 +88,14 @@ TEST(Projection, isInFrontOfCamera) {
TEST(AutoCalibration, ProjectionShiftPrincipalPoint) {
Mat34 P1, P2;
+ // clang-format off
P1 << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0;
P2 << 1, 0, 3, 0,
0, 1, 4, 0,
0, 0, 1, 0;
+ // clang-format on
Mat34 P1_computed, P2_computed;
ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed);
ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed);
@@ -98,12 +106,14 @@ TEST(AutoCalibration, ProjectionShiftPrincipalPoint) {
TEST(AutoCalibration, ProjectionChangeAspectRatio) {
Mat34 P1, P2;
+ // clang-format off
P1 << 1, 0, 3, 0,
0, 1, 4, 0,
0, 0, 1, 0;
P2 << 1, 0, 3, 0,
0, 2, 4, 0,
0, 0, 1, 0;
+ // clang-format on
Mat34 P1_computed, P2_computed;
ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed);
ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed);
diff --git a/intern/libmv/libmv/multiview/resection.h b/intern/libmv/libmv/multiview/resection.h
index c142d6deeb2..e543827c932 100644
--- a/intern/libmv/libmv/multiview/resection.h
+++ b/intern/libmv/libmv/multiview/resection.h
@@ -33,23 +33,23 @@ namespace libmv {
namespace resection {
// x's are 2D image coordinates, (x,y,1), and X's are homogeneous four vectors.
-template<typename T>
-void Resection(const Matrix<T, 2, Dynamic> &x,
- const Matrix<T, 4, Dynamic> &X,
- Matrix<T, 3, 4> *P) {
+template <typename T>
+void Resection(const Matrix<T, 2, Dynamic>& x,
+ const Matrix<T, 4, Dynamic>& X,
+ Matrix<T, 3, 4>* P) {
int N = x.cols();
assert(X.cols() == N);
- Matrix<T, Dynamic, 12> design(2*N, 12);
+ Matrix<T, Dynamic, 12> design(2 * N, 12);
design.setZero();
for (int i = 0; i < N; i++) {
T xi = x(0, i);
T yi = x(1, i);
// See equation (7.2) on page 179 of H&Z.
- design.template block<1, 4>(2*i, 4) = -X.col(i).transpose();
- design.template block<1, 4>(2*i, 8) = yi*X.col(i).transpose();
- design.template block<1, 4>(2*i + 1, 0) = X.col(i).transpose();
- design.template block<1, 4>(2*i + 1, 8) = -xi*X.col(i).transpose();
+ design.template block<1, 4>(2 * i, 4) = -X.col(i).transpose();
+ design.template block<1, 4>(2 * i, 8) = yi * X.col(i).transpose();
+ design.template block<1, 4>(2 * i + 1, 0) = X.col(i).transpose();
+ design.template block<1, 4>(2 * i + 1, 8) = -xi * X.col(i).transpose();
}
Matrix<T, 12, 1> p;
Nullspace(&design, &p);
diff --git a/intern/libmv/libmv/multiview/resection_test.cc b/intern/libmv/libmv/multiview/resection_test.cc
index 368e2281cfa..fb075d02d69 100644
--- a/intern/libmv/libmv/multiview/resection_test.cc
+++ b/intern/libmv/libmv/multiview/resection_test.cc
@@ -20,12 +20,12 @@
#include <iostream>
+#include "libmv/logging/logging.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/resection.h"
#include "libmv/multiview/test_data_sets.h"
#include "libmv/numeric/numeric.h"
#include "testing/testing.h"
-#include "libmv/logging/logging.h"
namespace {
@@ -40,15 +40,15 @@ TEST(Resection, ThreeViews) {
Mat4X X(4, npoints);
X.block(0, 0, 3, npoints) = d.X;
X.row(3).setOnes();
- const Mat2X &x = d.x[i];
+ const Mat2X& x = d.x[i];
Mat34 P;
Resection(x, X, &P);
Mat34 P_expected = d.P(i);
// Because the P matrices are homogeneous, it is necessary to be tricky
// about the scale factor to make them match.
- P_expected *= 1/P_expected.array().abs().sum();
- P *= 1/P.array().abs().sum();
+ P_expected *= 1 / P_expected.array().abs().sum();
+ P *= 1 / P.array().abs().sum();
if (!((P(0, 0) > 0 && P_expected(0, 0) > 0) ||
(P(0, 0) < 0 && P_expected(0, 0) < 0))) {
P *= -1;
diff --git a/intern/libmv/libmv/multiview/test_data_sets.cc b/intern/libmv/libmv/multiview/test_data_sets.cc
index 110bde6f762..a927c166d19 100644
--- a/intern/libmv/libmv/multiview/test_data_sets.cc
+++ b/intern/libmv/libmv/multiview/test_data_sets.cc
@@ -22,24 +22,28 @@
#include <cmath>
-#include "libmv/numeric/numeric.h"
-#include "libmv/multiview/projection.h"
#include "libmv/multiview/fundamental.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
TwoViewDataSet TwoRealisticCameras(bool same_K) {
TwoViewDataSet d;
+ // clang-format off
d.K1 << 320, 0, 160,
0, 320, 120,
0, 0, 1;
+ // clang-format on
if (same_K) {
d.K2 = d.K1;
} else {
+ // clang-format off
d.K2 << 360, 0, 170,
0, 360, 110,
0, 0, 1;
+ // clang-format on
}
d.R1 = RotationAroundZ(-0.1);
d.R2 = RotationAroundX(-0.1);
@@ -59,10 +63,8 @@ TwoViewDataSet TwoRealisticCameras(bool same_K) {
return d;
}
-nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy,
- int cx, int cy,
- double distance,
- double jitter_amount) {
+nViewDatasetConfigator::nViewDatasetConfigator(
+ int fx, int fy, int cx, int cy, double distance, double jitter_amount) {
_fx = fx;
_fy = fy;
_cx = cx;
@@ -71,7 +73,8 @@ nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy,
_jitter_amount = jitter_amount;
}
-NViewDataSet NRealisticCamerasFull(int nviews, int npoints,
+NViewDataSet NRealisticCamerasFull(int nviews,
+ int npoints,
const nViewDatasetConfigator config) {
NViewDataSet d;
d.n = nviews;
@@ -102,9 +105,11 @@ NViewDataSet NRealisticCamerasFull(int nviews, int npoints,
jitter *= config._jitter_amount / camera_center.norm();
lookdir = -camera_center + jitter;
+ // clang-format off
d.K[i] << config._fx, 0, config._cx,
0, config._fy, config._cy,
0, 0, 1;
+ // clang-format on
d.R[i] = LookAt(lookdir);
d.t[i] = -d.R[i] * camera_center;
d.x[i] = Project(d.P(i), d.X);
@@ -113,9 +118,10 @@ NViewDataSet NRealisticCamerasFull(int nviews, int npoints,
return d;
}
-
-NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
- float view_ratio, unsigned min_projections,
+NViewDataSet NRealisticCamerasSparse(int nviews,
+ int npoints,
+ float view_ratio,
+ unsigned min_projections,
const nViewDatasetConfigator config) {
assert(view_ratio <= 1.0);
assert(view_ratio > 0.0);
@@ -137,7 +143,7 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
visibility.setZero();
Mat randoms(nviews, npoints);
randoms.setRandom();
- randoms = (randoms.array() + 1)/2.0;
+ randoms = (randoms.array() + 1) / 2.0;
unsigned num_visibles = 0;
for (size_t i = 0; i < nviews; ++i) {
num_visibles = 0;
@@ -174,15 +180,17 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
jitter *= config._jitter_amount / camera_center.norm();
lookdir = -camera_center + jitter;
+ // clang-format off
d.K[i] << config._fx, 0, config._cx,
0, config._fy, config._cy,
0, 0, 1;
+ // clang-format on
d.R[i] = LookAt(lookdir);
d.t[i] = -d.R[i] * camera_center;
j_visible = 0;
for (size_t j = 0; j < npoints; j++) {
if (visibility(i, j)) {
- X = d.X.col(j);
+ X = d.X.col(j);
d.x[i].col(j_visible) = Project(d.P(i), X);
d.x_ids[i][j_visible] = j;
j_visible++;
@@ -192,5 +200,4 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
return d;
}
-
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/test_data_sets.h b/intern/libmv/libmv/multiview/test_data_sets.h
index cf01663ca02..0c8785728bd 100644
--- a/intern/libmv/libmv/multiview/test_data_sets.h
+++ b/intern/libmv/libmv/multiview/test_data_sets.h
@@ -34,8 +34,8 @@ struct TwoViewDataSet {
Vec3 t1, t2; // Translation.
Mat34 P1, P2; // Projection matrix, P = K(R|t)
Mat3 F; // Fundamental matrix.
- Mat3X X; // 3D points.
- Mat2X x1, x2; // Projected points.
+ Mat3X X; // 3D points.
+ Mat2X x1, x2; // Projected points.
};
// Two cameras at (-1,-1,-10) and (2,1,-10) looking approximately towards z+.
@@ -45,13 +45,13 @@ TwoViewDataSet TwoRealisticCameras(bool same_K = false);
// and the other reconstruction data types is that all points are seen by all
// cameras.
struct NViewDataSet {
- vector<Mat3> K; // Internal parameters (fx, fy, etc).
- vector<Mat3> R; // Rotation.
- vector<Vec3> t; // Translation.
- vector<Vec3> C; // Camera centers.
- Mat3X X; // 3D points.
- vector<Mat2X> x; // Projected points; may have noise added.
- vector<Vecu> x_ids; // Indexes of points corresponding to the projections
+ vector<Mat3> K; // Internal parameters (fx, fy, etc).
+ vector<Mat3> R; // Rotation.
+ vector<Vec3> t; // Translation.
+ vector<Vec3> C; // Camera centers.
+ Mat3X X; // 3D points.
+ vector<Mat2X> x; // Projected points; may have noise added.
+ vector<Vecu> x_ids; // Indexes of points corresponding to the projections
int n; // Actual number of cameras.
@@ -83,22 +83,26 @@ struct nViewDatasetConfigator {
double _dist;
double _jitter_amount;
- nViewDatasetConfigator(int fx = 1000, int fy = 1000,
- int cx = 500, int cy = 500,
+ nViewDatasetConfigator(int fx = 1000,
+ int fy = 1000,
+ int cx = 500,
+ int cy = 500,
double distance = 1.5,
double jitter_amount = 0.01);
};
-NViewDataSet NRealisticCamerasFull(int nviews, int npoints,
- const nViewDatasetConfigator
- config = nViewDatasetConfigator());
+NViewDataSet NRealisticCamerasFull(
+ int nviews,
+ int npoints,
+ const nViewDatasetConfigator config = nViewDatasetConfigator());
// Generates sparse projections (not all points are projected)
-NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
- float view_ratio = 0.6,
- unsigned min_projections = 3,
- const nViewDatasetConfigator
- config = nViewDatasetConfigator());
+NViewDataSet NRealisticCamerasSparse(
+ int nviews,
+ int npoints,
+ float view_ratio = 0.6,
+ unsigned min_projections = 3,
+ const nViewDatasetConfigator config = nViewDatasetConfigator());
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/triangulation.cc b/intern/libmv/libmv/multiview/triangulation.cc
index 4d146c8f21b..568625de19d 100644
--- a/intern/libmv/libmv/multiview/triangulation.cc
+++ b/intern/libmv/libmv/multiview/triangulation.cc
@@ -20,15 +20,17 @@
#include "libmv/multiview/triangulation.h"
-#include "libmv/numeric/numeric.h"
#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
// HZ 12.2 pag.312
-void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
- const Mat34 &P2, const Vec2 &x2,
- Vec4 *X_homogeneous) {
+void TriangulateDLT(const Mat34& P1,
+ const Vec2& x1,
+ const Mat34& P2,
+ const Vec2& x2,
+ Vec4* X_homogeneous) {
Mat4 design;
for (int i = 0; i < 4; ++i) {
design(0, i) = x1(0) * P1(2, i) - P1(0, i);
@@ -39,9 +41,11 @@ void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
Nullspace(&design, X_homogeneous);
}
-void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
- const Mat34 &P2, const Vec2 &x2,
- Vec3 *X_euclidean) {
+void TriangulateDLT(const Mat34& P1,
+ const Vec2& x1,
+ const Mat34& P2,
+ const Vec2& x2,
+ Vec3* X_euclidean) {
Vec4 X_homogeneous;
TriangulateDLT(P1, x1, P2, x2, &X_homogeneous);
HomogeneousToEuclidean(X_homogeneous, X_euclidean);
diff --git a/intern/libmv/libmv/multiview/triangulation.h b/intern/libmv/libmv/multiview/triangulation.h
index be878890242..c538433eb8b 100644
--- a/intern/libmv/libmv/multiview/triangulation.h
+++ b/intern/libmv/libmv/multiview/triangulation.h
@@ -25,13 +25,17 @@
namespace libmv {
-void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
- const Mat34 &P2, const Vec2 &x2,
- Vec4 *X_homogeneous);
+void TriangulateDLT(const Mat34& P1,
+ const Vec2& x1,
+ const Mat34& P2,
+ const Vec2& x2,
+ Vec4* X_homogeneous);
-void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
- const Mat34 &P2, const Vec2 &x2,
- Vec3 *X_euclidean);
+void TriangulateDLT(const Mat34& P1,
+ const Vec2& x1,
+ const Mat34& P2,
+ const Vec2& x2,
+ Vec3* X_euclidean);
} // namespace libmv
diff --git a/intern/libmv/libmv/multiview/triangulation_test.cc b/intern/libmv/libmv/multiview/triangulation_test.cc
index 66d1ee25a62..54d20f4ee17 100644
--- a/intern/libmv/libmv/multiview/triangulation_test.cc
+++ b/intern/libmv/libmv/multiview/triangulation_test.cc
@@ -20,10 +20,10 @@
#include <iostream>
-#include "libmv/multiview/triangulation.h"
#include "libmv/multiview/fundamental.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/test_data_sets.h"
+#include "libmv/multiview/triangulation.h"
#include "libmv/numeric/numeric.h"
#include "testing/testing.h"
diff --git a/intern/libmv/libmv/multiview/two_view_kernel.h b/intern/libmv/libmv/multiview/two_view_kernel.h
index 7af0ed5ddab..4df99183ee0 100644
--- a/intern/libmv/libmv/multiview/two_view_kernel.h
+++ b/intern/libmv/libmv/multiview/two_view_kernel.h
@@ -30,10 +30,10 @@ namespace libmv {
namespace two_view {
namespace kernel {
-template<typename Solver, typename Unnormalizer>
+template <typename Solver, typename Unnormalizer>
struct NormalizedSolver {
enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES };
- static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *models) {
+ static void Solve(const Mat& x1, const Mat& x2, vector<Mat3>* models) {
assert(2 == x1.rows());
assert(MINIMUM_SAMPLES <= x1.cols());
assert(x1.rows() == x2.rows());
@@ -53,10 +53,10 @@ struct NormalizedSolver {
}
};
-template<typename Solver, typename Unnormalizer>
+template <typename Solver, typename Unnormalizer>
struct IsotropicNormalizedSolver {
enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES };
- static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *models) {
+ static void Solve(const Mat& x1, const Mat& x2, vector<Mat3>* models) {
assert(2 == x1.rows());
assert(MINIMUM_SAMPLES <= x1.cols());
assert(x1.rows() == x2.rows());
@@ -99,35 +99,32 @@ struct IsotropicNormalizedSolver {
//
// The fit routine must not clear existing entries in the vector of models; it
// should append new solutions to the end.
-template<typename SolverArg,
- typename ErrorArg,
- typename ModelArg = Mat3>
+template <typename SolverArg, typename ErrorArg, typename ModelArg = Mat3>
class Kernel {
public:
- Kernel(const Mat &x1, const Mat &x2) : x1_(x1), x2_(x2) {}
+ Kernel(const Mat& x1, const Mat& x2) : x1_(x1), x2_(x2) {}
typedef SolverArg Solver;
- typedef ModelArg Model;
+ typedef ModelArg Model;
enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES };
- void Fit(const vector<int> &samples, vector<Model> *models) const {
+ void Fit(const vector<int>& samples, vector<Model>* models) const {
Mat x1 = ExtractColumns(x1_, samples);
Mat x2 = ExtractColumns(x2_, samples);
Solver::Solve(x1, x2, models);
}
- double Error(int sample, const Model &model) const {
+ double Error(int sample, const Model& model) const {
return ErrorArg::Error(model,
static_cast<Vec>(x1_.col(sample)),
static_cast<Vec>(x2_.col(sample)));
}
- int NumSamples() const {
- return x1_.cols();
- }
- static void Solve(const Mat &x1, const Mat &x2, vector<Model> *models) {
+ int NumSamples() const { return x1_.cols(); }
+ static void Solve(const Mat& x1, const Mat& x2, vector<Model>* models) {
// By offering this, Kernel types can be passed to templates.
Solver::Solve(x1, x2, models);
}
+
protected:
- const Mat &x1_;
- const Mat &x2_;
+ const Mat& x1_;
+ const Mat& x2_;
};
} // namespace kernel
diff --git a/intern/libmv/libmv/numeric/dogleg.h b/intern/libmv/libmv/numeric/dogleg.h
index bf6f996ddaf..62abfbdcd4b 100644
--- a/intern/libmv/libmv/numeric/dogleg.h
+++ b/intern/libmv/libmv/numeric/dogleg.h
@@ -32,18 +32,18 @@
#include <cmath>
#include <cstdio>
-#include "libmv/numeric/numeric.h"
-#include "libmv/numeric/function_derivative.h"
#include "libmv/logging/logging.h"
+#include "libmv/numeric/function_derivative.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
-template<typename Function,
- typename Jacobian = NumericJacobian<Function>,
- typename Solver = Eigen::PartialPivLU<
- Matrix<typename Function::FMatrixType::RealScalar,
- Function::XMatrixType::RowsAtCompileTime,
- Function::XMatrixType::RowsAtCompileTime> > >
+template <typename Function,
+ typename Jacobian = NumericJacobian<Function>,
+ typename Solver = Eigen::PartialPivLU<
+ Matrix<typename Function::FMatrixType::RealScalar,
+ Function::XMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime>>>
class Dogleg {
public:
typedef typename Function::XMatrixType::RealScalar Scalar;
@@ -51,10 +51,12 @@ class Dogleg {
typedef typename Function::XMatrixType Parameters;
typedef Matrix<typename Function::FMatrixType::RealScalar,
Function::FMatrixType::RowsAtCompileTime,
- Function::XMatrixType::RowsAtCompileTime> JMatrixType;
+ Function::XMatrixType::RowsAtCompileTime>
+ JMatrixType;
typedef Matrix<typename JMatrixType::RealScalar,
JMatrixType::ColsAtCompileTime,
- JMatrixType::ColsAtCompileTime> AMatrixType;
+ JMatrixType::ColsAtCompileTime>
+ AMatrixType;
enum Status {
RUNNING,
@@ -71,34 +73,38 @@ class Dogleg {
STEEPEST_DESCENT,
};
- Dogleg(const Function &f)
- : f_(f), df_(f) {}
+ Dogleg(const Function& f) : f_(f), df_(f) {}
struct SolverParameters {
SolverParameters()
- : gradient_threshold(1e-16),
- relative_step_threshold(1e-16),
- error_threshold(1e-16),
- initial_trust_radius(1e0),
- max_iterations(500) {}
+ : gradient_threshold(1e-16),
+ relative_step_threshold(1e-16),
+ error_threshold(1e-16),
+ initial_trust_radius(1e0),
+ max_iterations(500) {}
Scalar gradient_threshold; // eps > max(J'*f(x))
Scalar relative_step_threshold; // eps > ||dx|| / ||x||
Scalar error_threshold; // eps > ||f(x)||
Scalar initial_trust_radius; // Initial u for solving normal equations.
- int max_iterations; // Maximum number of solver iterations.
+ int max_iterations; // Maximum number of solver iterations.
};
struct Results {
Scalar error_magnitude; // ||f(x)||
Scalar gradient_magnitude; // ||J'f(x)||
- int iterations;
+ int iterations;
Status status;
};
- Status Update(const Parameters &x, const SolverParameters &params,
- JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) {
+ Status Update(const Parameters& x,
+ const SolverParameters& params,
+ JMatrixType* J,
+ AMatrixType* A,
+ FVec* error,
+ Parameters* g) {
*J = df_(x);
- // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 directly.
+ // TODO(keir): In the case of m = n, avoid computing A and just do J^-1
+ // directly.
*A = (*J).transpose() * (*J);
*error = f_(x);
*g = (*J).transpose() * *error;
@@ -110,12 +116,12 @@ class Dogleg {
return RUNNING;
}
- Step SolveDoglegDirection(const Parameters &dx_sd,
- const Parameters &dx_gn,
+ Step SolveDoglegDirection(const Parameters& dx_sd,
+ const Parameters& dx_gn,
Scalar radius,
Scalar alpha,
- Parameters *dx_dl,
- Scalar *beta) {
+ Parameters* dx_dl,
+ Scalar* beta) {
Parameters a, b_minus_a;
// Solve for Dogleg step dx_dl.
if (dx_gn.norm() < radius) {
@@ -128,30 +134,29 @@ class Dogleg {
} else {
Parameters a = alpha * dx_sd;
- const Parameters &b = dx_gn;
+ const Parameters& b = dx_gn;
b_minus_a = a - b;
Scalar Mbma2 = b_minus_a.squaredNorm();
Scalar Ma2 = a.squaredNorm();
Scalar c = a.dot(b_minus_a);
- Scalar radius2 = radius*radius;
+ Scalar radius2 = radius * radius;
if (c <= 0) {
- *beta = (-c + sqrt(c*c + Mbma2*(radius2 - Ma2)))/(Mbma2);
+ *beta = (-c + sqrt(c * c + Mbma2 * (radius2 - Ma2))) / (Mbma2);
} else {
- *beta = (radius2 - Ma2) /
- (c + sqrt(c*c + Mbma2*(radius2 - Ma2)));
+ *beta = (radius2 - Ma2) / (c + sqrt(c * c + Mbma2 * (radius2 - Ma2)));
}
- *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha*dx_sd);
+ *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha * dx_sd);
return DOGLEG;
}
}
- Results minimize(Parameters *x_and_min) {
+ Results minimize(Parameters* x_and_min) {
SolverParameters params;
return minimize(params, x_and_min);
}
- Results minimize(const SolverParameters &params, Parameters *x_and_min) {
- Parameters &x = *x_and_min;
+ Results minimize(const SolverParameters& params, Parameters* x_and_min) {
+ Parameters& x = *x_and_min;
JMatrixType J;
AMatrixType A;
FVec error;
@@ -167,18 +172,21 @@ class Dogleg {
Parameters dx_sd; // Steepest descent step.
Parameters dx_dl; // Dogleg step.
Parameters dx_gn; // Gauss-Newton step.
- printf("iteration ||f(x)|| max(g) radius\n");
+ printf("iteration ||f(x)|| max(g) radius\n");
int i = 0;
for (; results.status == RUNNING && i < params.max_iterations; ++i) {
printf("%9d %12g %12g %12g",
- i, f_(x).norm(), g.array().abs().maxCoeff(), radius);
+ i,
+ f_(x).norm(),
+ g.array().abs().maxCoeff(),
+ radius);
- //LG << "iteration: " << i;
- //LG << "||f(x)||: " << f_(x).norm();
- //LG << "max(g): " << g.cwise().abs().maxCoeff();
- //LG << "radius: " << radius;
+ // LG << "iteration: " << i;
+ // LG << "||f(x)||: " << f_(x).norm();
+ // LG << "max(g): " << g.cwise().abs().maxCoeff();
+ // LG << "radius: " << radius;
// Eqn 3.19 from [1]
- Scalar alpha = g.squaredNorm() / (J*g).squaredNorm();
+ Scalar alpha = g.squaredNorm() / (J * g).squaredNorm();
// Solve for steepest descent direction dx_sd.
dx_sd = -g;
@@ -199,11 +207,11 @@ class Dogleg {
// Solve for dogleg direction dx_dl.
Scalar beta = 0;
- Step step = SolveDoglegDirection(dx_sd, dx_gn, radius, alpha,
- &dx_dl, &beta);
+ Step step =
+ SolveDoglegDirection(dx_sd, dx_gn, radius, alpha, &dx_dl, &beta);
Scalar e3 = params.relative_step_threshold;
- if (dx_dl.norm() < e3*(x.norm() + e3)) {
+ if (dx_dl.norm() < e3 * (x.norm() + e3)) {
results.status = RELATIVE_STEP_SIZE_TOO_SMALL;
break;
}
@@ -214,16 +222,19 @@ class Dogleg {
if (step == GAUSS_NEWTON) {
predicted = f_(x).squaredNorm();
} else if (step == STEEPEST_DESCENT) {
- predicted = radius * (2*alpha*g.norm() - radius) / 2 / alpha;
+ predicted = radius * (2 * alpha * g.norm() - radius) / 2 / alpha;
} else if (step == DOGLEG) {
- predicted = 0.5 * alpha * (1-beta)*(1-beta)*g.squaredNorm() +
- beta*(2-beta)*f_(x).squaredNorm();
+ predicted = 0.5 * alpha * (1 - beta) * (1 - beta) * g.squaredNorm() +
+ beta * (2 - beta) * f_(x).squaredNorm();
}
Scalar rho = actual / predicted;
- if (step == GAUSS_NEWTON) printf(" GAUSS");
- if (step == STEEPEST_DESCENT) printf(" STEE");
- if (step == DOGLEG) printf(" DOGL");
+ if (step == GAUSS_NEWTON)
+ printf(" GAUSS");
+ if (step == STEEPEST_DESCENT)
+ printf(" STEE");
+ if (step == DOGLEG)
+ printf(" DOGL");
printf(" %12g %12g %12g\n", rho, actual, predicted);
@@ -234,7 +245,7 @@ class Dogleg {
x_updated = true;
}
if (rho > 0.75) {
- radius = std::max(radius, 3*dx_dl.norm());
+ radius = std::max(radius, 3 * dx_dl.norm());
} else if (rho < 0.25) {
radius /= 2;
if (radius < e3 * (x.norm() + e3)) {
@@ -252,10 +263,10 @@ class Dogleg {
}
private:
- const Function &f_;
+ const Function& f_;
Jacobian df_;
};
-} // namespace mv
+} // namespace libmv
#endif // LIBMV_NUMERIC_DOGLEG_H
diff --git a/intern/libmv/libmv/numeric/dogleg_test.cc b/intern/libmv/libmv/numeric/dogleg_test.cc
index 90c46c31672..a5ab1957632 100644
--- a/intern/libmv/libmv/numeric/dogleg_test.cc
+++ b/intern/libmv/libmv/numeric/dogleg_test.cc
@@ -18,8 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "testing/testing.h"
#include "libmv/numeric/dogleg.h"
+#include "testing/testing.h"
using namespace libmv;
@@ -29,26 +29,26 @@ class F {
public:
typedef Vec4 FMatrixType;
typedef Vec3 XMatrixType;
- Vec4 operator()(const Vec3 &x) const {
+ Vec4 operator()(const Vec3& x) const {
double x1 = x.x() - 2;
double y1 = x.y() - 5;
double z1 = x.z();
- Vec4 fx; fx << x1*x1 + z1*z1,
- y1*y1 + z1*z1,
- z1*z1,
- x1*x1;
+ Vec4 fx;
+ fx << x1 * x1 + z1 * z1, y1 * y1 + z1 * z1, z1 * z1, x1 * x1;
return fx;
}
};
TEST(Dogleg, SimpleCase) {
- Vec3 x; x << 0.76026643, -30.01799744, 0.55192142;
+ Vec3 x;
+ x << 0.76026643, -30.01799744, 0.55192142;
F f;
Dogleg<F>::SolverParameters params;
Dogleg<F> lm(f);
/* TODO(sergey): Better error handling. */
/* Dogleg<F>::Results results = */ lm.minimize(params, &x);
- Vec3 expected_min_x; expected_min_x << 2, 5, 0;
+ Vec3 expected_min_x;
+ expected_min_x << 2, 5, 0;
EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5);
}
@@ -59,20 +59,21 @@ class F32 {
public:
typedef Vec2 FMatrixType;
typedef Vec2 XMatrixType;
- Vec2 operator()(const Vec2 &x) const {
+ Vec2 operator()(const Vec2& x) const {
double x1 = x(0);
- double x2 = 10*x(0)/(x(0) + 0.1) + 2*x(1)*x(1);
- Vec2 fx; fx << x1, x2;
+ double x2 = 10 * x(0) / (x(0) + 0.1) + 2 * x(1) * x(1);
+ Vec2 fx;
+ fx << x1, x2;
return fx;
}
};
class JF32 {
public:
- JF32(const F32 &f) { (void) f; }
- Mat2 operator()(const Vec2 &x) {
- Mat2 J; J << 1, 0,
- 1./pow(x(0) + 0.1, 2), 4*x(1)*x(1);
+ JF32(const F32& f) { (void)f; }
+ Mat2 operator()(const Vec2& x) {
+ Mat2 J;
+ J << 1, 0, 1. / pow(x(0) + 0.1, 2), 4 * x(1) * x(1);
return J;
}
};
diff --git a/intern/libmv/libmv/numeric/function_derivative.h b/intern/libmv/libmv/numeric/function_derivative.h
index 9820885f04e..30d7c4d34e9 100644
--- a/intern/libmv/libmv/numeric/function_derivative.h
+++ b/intern/libmv/libmv/numeric/function_derivative.h
@@ -23,8 +23,8 @@
#include <cmath>
-#include "libmv/numeric/numeric.h"
#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
@@ -36,7 +36,7 @@ enum NumericJacobianMode {
FORWARD,
};
-template<typename Function, NumericJacobianMode mode = CENTRAL>
+template <typename Function, NumericJacobianMode mode = CENTRAL>
class NumericJacobian {
public:
typedef typename Function::XMatrixType Parameters;
@@ -45,12 +45,12 @@ class NumericJacobian {
typedef Matrix<typename Function::FMatrixType::RealScalar,
Function::FMatrixType::RowsAtCompileTime,
Function::XMatrixType::RowsAtCompileTime>
- JMatrixType;
+ JMatrixType;
- NumericJacobian(const Function &f) : f_(f) {}
+ NumericJacobian(const Function& f) : f_(f) {}
// TODO(keir): Perhaps passing the jacobian back by value is not a good idea.
- JMatrixType operator()(const Parameters &x) {
+ JMatrixType operator()(const Parameters& x) {
// Empirically determined constant.
Parameters eps = x.array().abs() * XScalar(1e-5);
// To handle cases where a paremeter is exactly zero, instead use the mean
@@ -87,12 +87,13 @@ class NumericJacobian {
}
return jacobian;
}
+
private:
- const Function &f_;
+ const Function& f_;
};
-template<typename Function, typename Jacobian>
-bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) {
+template <typename Function, typename Jacobian>
+bool CheckJacobian(const Function& f, const typename Function::XMatrixType& x) {
Jacobian j_analytic(f);
NumericJacobian<Function> j_numeric(f);
diff --git a/intern/libmv/libmv/numeric/function_derivative_test.cc b/intern/libmv/libmv/numeric/function_derivative_test.cc
index 8d976d3e9a0..defeedaa8a4 100644
--- a/intern/libmv/libmv/numeric/function_derivative_test.cc
+++ b/intern/libmv/libmv/numeric/function_derivative_test.cc
@@ -18,9 +18,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "testing/testing.h"
-#include "libmv/numeric/numeric.h"
#include "libmv/numeric/function_derivative.h"
+#include "libmv/numeric/numeric.h"
+#include "testing/testing.h"
using namespace libmv;
@@ -30,22 +30,22 @@ class F {
public:
typedef Vec2 FMatrixType;
typedef Vec3 XMatrixType;
- Vec2 operator()(const Vec3 &x) const {
+ Vec2 operator()(const Vec3& x) const {
Vec2 fx;
- fx << 0.19*x(0) + 0.19*x(1)*x(1) + x(2),
- 3*sin(x(0)) + 2*cos(x(1));
+ fx << 0.19 * x(0) + 0.19 * x(1) * x(1) + x(2),
+ 3 * sin(x(0)) + 2 * cos(x(1));
return fx;
}
- Mat23 J(const Vec3 &x) const {
+ Mat23 J(const Vec3& x) const {
Mat23 jacobian;
- jacobian << 0.19, 2*0.19*x(1), 1.0,
- 3*cos(x(0)), -2*sin(x(1)), 0;
+ jacobian << 0.19, 2 * 0.19 * x(1), 1.0, 3 * cos(x(0)), -2 * sin(x(1)), 0;
return jacobian;
}
};
TEST(FunctionDerivative, SimpleCase) {
- Vec3 x; x << 0.76026643, 0.01799744, 0.55192142;
+ Vec3 x;
+ x << 0.76026643, 0.01799744, 0.55192142;
F f;
NumericJacobian<F, CENTRAL> J(f);
EXPECT_MATRIX_NEAR(f.J(x), J(x), 1e-8);
diff --git a/intern/libmv/libmv/numeric/levenberg_marquardt.h b/intern/libmv/libmv/numeric/levenberg_marquardt.h
index 2af9a62cf7b..30c04a5ad5c 100644
--- a/intern/libmv/libmv/numeric/levenberg_marquardt.h
+++ b/intern/libmv/libmv/numeric/levenberg_marquardt.h
@@ -31,18 +31,18 @@
#include <cmath>
-#include "libmv/numeric/numeric.h"
-#include "libmv/numeric/function_derivative.h"
#include "libmv/logging/logging.h"
+#include "libmv/numeric/function_derivative.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
-template<typename Function,
- typename Jacobian = NumericJacobian<Function>,
- typename Solver = Eigen::PartialPivLU<
- Matrix<typename Function::FMatrixType::RealScalar,
- Function::XMatrixType::RowsAtCompileTime,
- Function::XMatrixType::RowsAtCompileTime> > >
+template <typename Function,
+ typename Jacobian = NumericJacobian<Function>,
+ typename Solver = Eigen::PartialPivLU<
+ Matrix<typename Function::FMatrixType::RealScalar,
+ Function::XMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime>>>
class LevenbergMarquardt {
public:
typedef typename Function::XMatrixType::RealScalar Scalar;
@@ -50,10 +50,12 @@ class LevenbergMarquardt {
typedef typename Function::XMatrixType Parameters;
typedef Matrix<typename Function::FMatrixType::RealScalar,
Function::FMatrixType::RowsAtCompileTime,
- Function::XMatrixType::RowsAtCompileTime> JMatrixType;
+ Function::XMatrixType::RowsAtCompileTime>
+ JMatrixType;
typedef Matrix<typename JMatrixType::RealScalar,
JMatrixType::ColsAtCompileTime,
- JMatrixType::ColsAtCompileTime> AMatrixType;
+ JMatrixType::ColsAtCompileTime>
+ AMatrixType;
// TODO(keir): Some of these knobs can be derived from each other and
// removed, instead of requiring the user to set them.
@@ -65,32 +67,35 @@ class LevenbergMarquardt {
HIT_MAX_ITERATIONS,
};
- LevenbergMarquardt(const Function &f)
- : f_(f), df_(f) {}
+ LevenbergMarquardt(const Function& f) : f_(f), df_(f) {}
struct SolverParameters {
SolverParameters()
- : gradient_threshold(1e-16),
- relative_step_threshold(1e-16),
- error_threshold(1e-16),
- initial_scale_factor(1e-3),
- max_iterations(100) {}
+ : gradient_threshold(1e-16),
+ relative_step_threshold(1e-16),
+ error_threshold(1e-16),
+ initial_scale_factor(1e-3),
+ max_iterations(100) {}
Scalar gradient_threshold; // eps > max(J'*f(x))
Scalar relative_step_threshold; // eps > ||dx|| / ||x||
Scalar error_threshold; // eps > ||f(x)||
Scalar initial_scale_factor; // Initial u for solving normal equations.
- int max_iterations; // Maximum number of solver iterations.
+ int max_iterations; // Maximum number of solver iterations.
};
struct Results {
Scalar error_magnitude; // ||f(x)||
Scalar gradient_magnitude; // ||J'f(x)||
- int iterations;
+ int iterations;
Status status;
};
- Status Update(const Parameters &x, const SolverParameters &params,
- JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) {
+ Status Update(const Parameters& x,
+ const SolverParameters& params,
+ JMatrixType* J,
+ AMatrixType* A,
+ FVec* error,
+ Parameters* g) {
*J = df_(x);
*A = (*J).transpose() * (*J);
*error = -f_(x);
@@ -103,13 +108,13 @@ class LevenbergMarquardt {
return RUNNING;
}
- Results minimize(Parameters *x_and_min) {
+ Results minimize(Parameters* x_and_min) {
SolverParameters params;
minimize(params, x_and_min);
}
- Results minimize(const SolverParameters &params, Parameters *x_and_min) {
- Parameters &x = *x_and_min;
+ Results minimize(const SolverParameters& params, Parameters* x_and_min) {
+ Parameters& x = *x_and_min;
JMatrixType J;
AMatrixType A;
FVec error;
@@ -118,7 +123,7 @@ class LevenbergMarquardt {
Results results;
results.status = Update(x, params, &J, &A, &error, &g);
- Scalar u = Scalar(params.initial_scale_factor*A.diagonal().maxCoeff());
+ Scalar u = Scalar(params.initial_scale_factor * A.diagonal().maxCoeff());
Scalar v = 2;
Parameters dx, x_new;
@@ -130,7 +135,8 @@ class LevenbergMarquardt {
VLOG(3) << "u: " << u;
VLOG(3) << "v: " << v;
- AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols());
+ AMatrixType A_augmented =
+ A + u * AMatrixType::Identity(J.cols(), J.cols());
Solver solver(A_augmented);
dx = solver.solve(g);
bool solved = (A_augmented * dx).isApprox(g);
@@ -146,14 +152,14 @@ class LevenbergMarquardt {
// Rho is the ratio of the actual reduction in error to the reduction
// in error that would be obtained if the problem was linear.
// See [1] for details.
- Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm())
- / dx.dot(u*dx + g));
+ Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm()) /
+ dx.dot(u * dx + g));
if (rho > 0) {
// Accept the Gauss-Newton step because the linear model fits well.
x = x_new;
results.status = Update(x, params, &J, &A, &error, &g);
- Scalar tmp = Scalar(2*rho-1);
- u = u*std::max(1/3., 1 - (tmp*tmp*tmp));
+ Scalar tmp = Scalar(2 * rho - 1);
+ u = u * std::max(1 / 3., 1 - (tmp * tmp * tmp));
v = 2;
continue;
}
@@ -174,10 +180,10 @@ class LevenbergMarquardt {
}
private:
- const Function &f_;
+ const Function& f_;
Jacobian df_;
};
-} // namespace mv
+} // namespace libmv
#endif // LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H
diff --git a/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc
index fc3f9ebbb29..805aac275b4 100644
--- a/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc
+++ b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc
@@ -18,8 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "testing/testing.h"
#include "libmv/numeric/levenberg_marquardt.h"
+#include "testing/testing.h"
using namespace libmv;
@@ -29,14 +29,12 @@ class F {
public:
typedef Vec4 FMatrixType;
typedef Vec3 XMatrixType;
- Vec4 operator()(const Vec3 &x) const {
+ Vec4 operator()(const Vec3& x) const {
double x1 = x.x() - 2;
double y1 = x.y() - 5;
double z1 = x.z();
- Vec4 fx; fx << x1*x1 + z1*z1,
- y1*y1 + z1*z1,
- z1*z1,
- x1*x1;
+ Vec4 fx;
+ fx << x1 * x1 + z1 * z1, y1 * y1 + z1 * z1, z1 * z1, x1 * x1;
return fx;
}
};
diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc
index 3fc1e3b2bfd..b7660950c2a 100644
--- a/intern/libmv/libmv/numeric/numeric.cc
+++ b/intern/libmv/libmv/numeric/numeric.cc
@@ -18,7 +18,6 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-
#include "libmv/numeric/numeric.h"
namespace libmv {
@@ -27,9 +26,11 @@ Mat3 RotationAroundX(double angle) {
double c, s;
sincos(angle, &s, &c);
Mat3 R;
+ // clang-format off
R << 1, 0, 0,
0, c, -s,
0, s, c;
+ // clang-format on
return R;
}
@@ -37,9 +38,11 @@ Mat3 RotationAroundY(double angle) {
double c, s;
sincos(angle, &s, &c);
Mat3 R;
+ // clang-format off
R << c, 0, s,
0, 1, 0,
-s, 0, c;
+ // clang-format on
return R;
}
@@ -47,14 +50,15 @@ Mat3 RotationAroundZ(double angle) {
double c, s;
sincos(angle, &s, &c);
Mat3 R;
+ // clang-format off
R << c, -s, 0,
s, c, 0,
0, 0, 1;
+ // clang-format on
return R;
}
-
-Mat3 RotationRodrigues(const Vec3 &axis) {
+Mat3 RotationRodrigues(const Vec3& axis) {
double theta = axis.norm();
Vec3 w = axis / theta;
Mat3 W = CrossProductMatrix(w);
@@ -62,7 +66,6 @@ Mat3 RotationRodrigues(const Vec3 &axis) {
return Mat3::Identity() + sin(theta) * W + (1 - cos(theta)) * W * W;
}
-
Mat3 LookAt(Vec3 center) {
Vec3 zc = center.normalized();
Vec3 xc = Vec3::UnitY().cross(zc).normalized();
@@ -74,19 +77,21 @@ Mat3 LookAt(Vec3 center) {
return R;
}
-Mat3 CrossProductMatrix(const Vec3 &x) {
+Mat3 CrossProductMatrix(const Vec3& x) {
Mat3 X;
+ // clang-format off
X << 0, -x(2), x(1),
x(2), 0, -x(0),
-x(1), x(0), 0;
+ // clang-format on
return X;
}
-void MeanAndVarianceAlongRows(const Mat &A,
- Vec *mean_pointer,
- Vec *variance_pointer) {
- Vec &mean = *mean_pointer;
- Vec &variance = *variance_pointer;
+void MeanAndVarianceAlongRows(const Mat& A,
+ Vec* mean_pointer,
+ Vec* variance_pointer) {
+ Vec& mean = *mean_pointer;
+ Vec& variance = *variance_pointer;
int n = A.rows();
int m = A.cols();
mean.resize(n);
@@ -108,29 +113,28 @@ void MeanAndVarianceAlongRows(const Mat &A,
}
}
-void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) {
+void HorizontalStack(const Mat& left, const Mat& right, Mat* stacked) {
assert(left.rows() == right.rows());
int n = left.rows();
int m1 = left.cols();
int m2 = right.cols();
stacked->resize(n, m1 + m2);
- stacked->block(0, 0, n, m1) = left;
+ stacked->block(0, 0, n, m1) = left;
stacked->block(0, m1, n, m2) = right;
}
-void MatrixColumn(const Mat &A, int i, Vec2 *v) {
+void MatrixColumn(const Mat& A, int i, Vec2* v) {
assert(A.rows() == 2);
*v << A(0, i), A(1, i);
}
-void MatrixColumn(const Mat &A, int i, Vec3 *v) {
+void MatrixColumn(const Mat& A, int i, Vec3* v) {
assert(A.rows() == 3);
*v << A(0, i), A(1, i), A(2, i);
}
-void MatrixColumn(const Mat &A, int i, Vec4 *v) {
+void MatrixColumn(const Mat& A, int i, Vec4* v) {
assert(A.rows() == 4);
*v << A(0, i), A(1, i), A(2, i), A(3, i);
}
} // namespace libmv
-
diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h
index f5478bee6ab..e3d44226338 100644
--- a/intern/libmv/libmv/numeric/numeric.h
+++ b/intern/libmv/libmv/numeric/numeric.h
@@ -34,10 +34,9 @@
#include <Eigen/SVD>
#if !defined(__MINGW64__)
-# if defined(_WIN32) || defined(__APPLE__) || \
- defined(__FreeBSD__) || defined(__NetBSD__) || \
- defined(__HAIKU__)
-inline void sincos(double x, double *sinx, double *cosx) {
+# if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) || \
+ defined(__NetBSD__) || defined(__HAIKU__)
+inline void sincos(double x, double* sinx, double* cosx) {
*sinx = sin(x);
*cosx = cos(x);
}
@@ -46,11 +45,11 @@ inline void sincos(double x, double *sinx, double *cosx) {
#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
inline long lround(double d) {
- return (long)(d>0 ? d+0.5 : ceil(d-0.5));
+ return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5));
}
# if _MSC_VER < 1800
inline int round(double d) {
- return (d>0) ? int(d+0.5) : int(d-0.5);
+ return (d > 0) ? int(d + 0.5) : int(d - 0.5);
}
# endif // _MSC_VER < 1800
typedef unsigned int uint;
@@ -92,25 +91,25 @@ typedef Eigen::Matrix<double, 4, 4, Eigen::RowMajor> RMat4;
typedef Eigen::Matrix<double, 2, Eigen::Dynamic> Mat2X;
typedef Eigen::Matrix<double, 3, Eigen::Dynamic> Mat3X;
typedef Eigen::Matrix<double, 4, Eigen::Dynamic> Mat4X;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9;
typedef Eigen::Matrix<double, Eigen::Dynamic, 15> MatX15;
typedef Eigen::Matrix<double, Eigen::Dynamic, 16> MatX16;
typedef Eigen::Vector2d Vec2;
typedef Eigen::Vector3d Vec3;
typedef Eigen::Vector4d Vec4;
-typedef Eigen::Matrix<double, 5, 1> Vec5;
-typedef Eigen::Matrix<double, 6, 1> Vec6;
-typedef Eigen::Matrix<double, 7, 1> Vec7;
-typedef Eigen::Matrix<double, 8, 1> Vec8;
-typedef Eigen::Matrix<double, 9, 1> Vec9;
+typedef Eigen::Matrix<double, 5, 1> Vec5;
+typedef Eigen::Matrix<double, 6, 1> Vec6;
+typedef Eigen::Matrix<double, 7, 1> Vec7;
+typedef Eigen::Matrix<double, 8, 1> Vec8;
+typedef Eigen::Matrix<double, 9, 1> Vec9;
typedef Eigen::Matrix<double, 10, 1> Vec10;
typedef Eigen::Matrix<double, 11, 1> Vec11;
typedef Eigen::Matrix<double, 12, 1> Vec12;
@@ -133,15 +132,13 @@ typedef Eigen::Vector2i Vec2i;
typedef Eigen::Vector3i Vec3i;
typedef Eigen::Vector4i Vec4i;
-typedef Eigen::Matrix<float,
- Eigen::Dynamic,
- Eigen::Dynamic,
- Eigen::RowMajor> RMatf;
+typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
+ RMatf;
typedef Eigen::NumTraits<double> EigenDouble;
-using Eigen::Map;
using Eigen::Dynamic;
+using Eigen::Map;
using Eigen::Matrix;
// Find U, s, and VT such that
@@ -149,7 +146,7 @@ using Eigen::Matrix;
// A = U * diag(s) * VT
//
template <typename TMat, typename TVec>
-inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) {
+inline void SVD(TMat* /*A*/, Vec* /*s*/, Mat* /*U*/, Mat* /*VT*/) {
assert(0);
}
@@ -158,11 +155,11 @@ inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) {
// Destroys A and resizes x if necessary.
// TODO(maclean): Take the SVD of the transpose instead of this zero padding.
template <typename TMat, typename TVec>
-double Nullspace(TMat *A, TVec *nullspace) {
+double Nullspace(TMat* A, TVec* nullspace) {
Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
- (*nullspace) = svd.matrixV().col(A->cols()-1);
+ (*nullspace) = svd.matrixV().col(A->cols() - 1);
if (A->rows() >= A->cols())
- return svd.singularValues()(A->cols()-1);
+ return svd.singularValues()(A->cols() - 1);
else
return 0.0;
}
@@ -173,55 +170,55 @@ double Nullspace(TMat *A, TVec *nullspace) {
// the singluar value corresponding to the solution x1. Destroys A and resizes
// x if necessary.
template <typename TMat, typename TVec1, typename TVec2>
-double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) {
+double Nullspace2(TMat* A, TVec1* x1, TVec2* x2) {
Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
*x1 = svd.matrixV().col(A->cols() - 1);
*x2 = svd.matrixV().col(A->cols() - 2);
if (A->rows() >= A->cols())
- return svd.singularValues()(A->cols()-1);
+ return svd.singularValues()(A->cols() - 1);
else
return 0.0;
}
// In place transpose for square matrices.
-template<class TA>
-inline void TransposeInPlace(TA *A) {
+template <class TA>
+inline void TransposeInPlace(TA* A) {
*A = A->transpose().eval();
}
-template<typename TVec>
-inline double NormL1(const TVec &x) {
+template <typename TVec>
+inline double NormL1(const TVec& x) {
return x.array().abs().sum();
}
-template<typename TVec>
-inline double NormL2(const TVec &x) {
+template <typename TVec>
+inline double NormL2(const TVec& x) {
return x.norm();
}
-template<typename TVec>
-inline double NormLInfinity(const TVec &x) {
+template <typename TVec>
+inline double NormLInfinity(const TVec& x) {
return x.array().abs().maxCoeff();
}
-template<typename TVec>
-inline double DistanceL1(const TVec &x, const TVec &y) {
+template <typename TVec>
+inline double DistanceL1(const TVec& x, const TVec& y) {
return (x - y).array().abs().sum();
}
-template<typename TVec>
-inline double DistanceL2(const TVec &x, const TVec &y) {
+template <typename TVec>
+inline double DistanceL2(const TVec& x, const TVec& y) {
return (x - y).norm();
}
-template<typename TVec>
-inline double DistanceLInfinity(const TVec &x, const TVec &y) {
+template <typename TVec>
+inline double DistanceLInfinity(const TVec& x, const TVec& y) {
return (x - y).array().abs().maxCoeff();
}
// Normalize a vector with the L1 norm, and return the norm before it was
// normalized.
-template<typename TVec>
-inline double NormalizeL1(TVec *x) {
+template <typename TVec>
+inline double NormalizeL1(TVec* x) {
double norm = NormL1(*x);
*x /= norm;
return norm;
@@ -229,8 +226,8 @@ inline double NormalizeL1(TVec *x) {
// Normalize a vector with the L2 norm, and return the norm before it was
// normalized.
-template<typename TVec>
-inline double NormalizeL2(TVec *x) {
+template <typename TVec>
+inline double NormalizeL2(TVec* x) {
double norm = NormL2(*x);
*x /= norm;
return norm;
@@ -238,15 +235,15 @@ inline double NormalizeL2(TVec *x) {
// Normalize a vector with the L^Infinity norm, and return the norm before it
// was normalized.
-template<typename TVec>
-inline double NormalizeLInfinity(TVec *x) {
+template <typename TVec>
+inline double NormalizeLInfinity(TVec* x) {
double norm = NormLInfinity(*x);
*x /= norm;
return norm;
}
// Return the square of a number.
-template<typename T>
+template <typename T>
inline T Square(T x) {
return x * x;
}
@@ -258,7 +255,7 @@ Mat3 RotationAroundZ(double angle);
// Returns the rotation matrix of a rotation of angle |axis| around axis.
// This is computed using the Rodrigues formula, see:
// http://mathworld.wolfram.com/RodriguesRotationFormula.html
-Mat3 RotationRodrigues(const Vec3 &axis);
+Mat3 RotationRodrigues(const Vec3& axis);
// Make a rotation matrix such that center becomes the direction of the
// positive z-axis, and y is oriented close to up.
@@ -266,177 +263,173 @@ Mat3 LookAt(Vec3 center);
// Return a diagonal matrix from a vector containg the diagonal values.
template <typename TVec>
-inline Mat Diag(const TVec &x) {
+inline Mat Diag(const TVec& x) {
return x.asDiagonal();
}
-template<typename TMat>
-inline double FrobeniusNorm(const TMat &A) {
+template <typename TMat>
+inline double FrobeniusNorm(const TMat& A) {
return sqrt(A.array().abs2().sum());
}
-template<typename TMat>
-inline double FrobeniusDistance(const TMat &A, const TMat &B) {
+template <typename TMat>
+inline double FrobeniusDistance(const TMat& A, const TMat& B) {
return FrobeniusNorm(A - B);
}
-inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) {
+inline Vec3 CrossProduct(const Vec3& x, const Vec3& y) {
return x.cross(y);
}
-Mat3 CrossProductMatrix(const Vec3 &x);
+Mat3 CrossProductMatrix(const Vec3& x);
-void MeanAndVarianceAlongRows(const Mat &A,
- Vec *mean_pointer,
- Vec *variance_pointer);
+void MeanAndVarianceAlongRows(const Mat& A,
+ Vec* mean_pointer,
+ Vec* variance_pointer);
#if defined(_WIN32)
- // TODO(bomboze): un-#if this for both platforms once tested under Windows
- /* This solution was extensively discussed here
- http://forum.kde.org/viewtopic.php?f=74&t=61940 */
- #define SUM_OR_DYNAMIC(x, y) (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x+y)
-
- template<typename Derived1, typename Derived2>
- struct hstack_return {
- typedef typename Derived1::Scalar Scalar;
- enum {
- RowsAtCompileTime = Derived1::RowsAtCompileTime,
- ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime,
- Derived2::ColsAtCompileTime),
- Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
- MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime,
- MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime,
- Derived2::MaxColsAtCompileTime)
- };
- typedef Eigen::Matrix<Scalar,
- RowsAtCompileTime,
- ColsAtCompileTime,
- Options,
- MaxRowsAtCompileTime,
- MaxColsAtCompileTime> type;
+// TODO(bomboze): un-#if this for both platforms once tested under Windows
+/* This solution was extensively discussed here
+ http://forum.kde.org/viewtopic.php?f=74&t=61940 */
+# define SUM_OR_DYNAMIC(x, y) \
+ (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x + y)
+
+template <typename Derived1, typename Derived2>
+struct hstack_return {
+ typedef typename Derived1::Scalar Scalar;
+ enum {
+ RowsAtCompileTime = Derived1::RowsAtCompileTime,
+ ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime,
+ Derived2::ColsAtCompileTime),
+ Options = Derived1::Flags & Eigen::RowMajorBit ? Eigen::RowMajor : 0,
+ MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime,
+ Derived2::MaxColsAtCompileTime)
};
-
- template<typename Derived1, typename Derived2>
- typename hstack_return<Derived1, Derived2>::type
- HStack(const Eigen::MatrixBase<Derived1>& lhs,
- const Eigen::MatrixBase<Derived2>& rhs) {
- typename hstack_return<Derived1, Derived2>::type res;
- res.resize(lhs.rows(), lhs.cols()+rhs.cols());
- res << lhs, rhs;
- return res;
- };
-
-
- template<typename Derived1, typename Derived2>
- struct vstack_return {
- typedef typename Derived1::Scalar Scalar;
- enum {
- RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime,
- Derived2::RowsAtCompileTime),
- ColsAtCompileTime = Derived1::ColsAtCompileTime,
- Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
- MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime,
- Derived2::MaxRowsAtCompileTime),
- MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime
- };
- typedef Eigen::Matrix<Scalar,
- RowsAtCompileTime,
- ColsAtCompileTime,
- Options,
- MaxRowsAtCompileTime,
- MaxColsAtCompileTime> type;
+ typedef Eigen::Matrix<Scalar,
+ RowsAtCompileTime,
+ ColsAtCompileTime,
+ Options,
+ MaxRowsAtCompileTime,
+ MaxColsAtCompileTime>
+ type;
+};
+
+template <typename Derived1, typename Derived2>
+typename hstack_return<Derived1, Derived2>::type HStack(
+ const Eigen::MatrixBase<Derived1>& lhs,
+ const Eigen::MatrixBase<Derived2>& rhs) {
+ typename hstack_return<Derived1, Derived2>::type res;
+ res.resize(lhs.rows(), lhs.cols() + rhs.cols());
+ res << lhs, rhs;
+ return res;
+};
+
+template <typename Derived1, typename Derived2>
+struct vstack_return {
+ typedef typename Derived1::Scalar Scalar;
+ enum {
+ RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime,
+ Derived2::RowsAtCompileTime),
+ ColsAtCompileTime = Derived1::ColsAtCompileTime,
+ Options = Derived1::Flags & Eigen::RowMajorBit ? Eigen::RowMajor : 0,
+ MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime,
+ Derived2::MaxRowsAtCompileTime),
+ MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime
};
-
- template<typename Derived1, typename Derived2>
- typename vstack_return<Derived1, Derived2>::type
- VStack(const Eigen::MatrixBase<Derived1>& lhs,
- const Eigen::MatrixBase<Derived2>& rhs) {
- typename vstack_return<Derived1, Derived2>::type res;
- res.resize(lhs.rows()+rhs.rows(), lhs.cols());
- res << lhs, rhs;
- return res;
- };
-
+ typedef Eigen::Matrix<Scalar,
+ RowsAtCompileTime,
+ ColsAtCompileTime,
+ Options,
+ MaxRowsAtCompileTime,
+ MaxColsAtCompileTime>
+ type;
+};
+
+template <typename Derived1, typename Derived2>
+typename vstack_return<Derived1, Derived2>::type VStack(
+ const Eigen::MatrixBase<Derived1>& lhs,
+ const Eigen::MatrixBase<Derived2>& rhs) {
+ typename vstack_return<Derived1, Derived2>::type res;
+ res.resize(lhs.rows() + rhs.rows(), lhs.cols());
+ res << lhs, rhs;
+ return res;
+};
#else // _WIN32
- // Since it is not possible to typedef privately here, use a macro.
- // Always take dynamic columns if either side is dynamic.
- #define COLS \
- ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \
- ? Eigen::Dynamic : (ColsLeft + ColsRight))
-
- // Same as above, except that prefer fixed size if either is fixed.
- #define ROWS \
- ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \
- ? Eigen::Dynamic \
- : ((RowsLeft == Eigen::Dynamic) \
- ? RowsRight \
- : RowsLeft \
- ) \
- )
-
- // TODO(keir): Add a static assert if both rows are at compiletime.
- template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
- Eigen::Matrix<T, ROWS, COLS>
- HStack(const Eigen::Matrix<T, RowsLeft, ColsLeft> &left,
- const Eigen::Matrix<T, RowsRight, ColsRight> &right) {
- assert(left.rows() == right.rows());
- int n = left.rows();
- int m1 = left.cols();
- int m2 = right.cols();
-
- Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2);
- stacked.block(0, 0, n, m1) = left;
- stacked.block(0, m1, n, m2) = right;
- return stacked;
- }
-
- // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but
- // the duplication is worse.
- // TODO(keir): Add a static assert if both rows are at compiletime.
- // TODO(keir): Mail eigen list about making this work for general expressions
- // rather than only matrix types.
- template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
- Eigen::Matrix<T, COLS, ROWS>
- VStack(const Eigen::Matrix<T, ColsLeft, RowsLeft> &top,
- const Eigen::Matrix<T, ColsRight, RowsRight> &bottom) {
- assert(top.cols() == bottom.cols());
- int n1 = top.rows();
- int n2 = bottom.rows();
- int m = top.cols();
-
- Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m);
- stacked.block(0, 0, n1, m) = top;
- stacked.block(n1, 0, n2, m) = bottom;
- return stacked;
- }
- #undef COLS
- #undef ROWS
-#endif // _WIN32
+// Since it is not possible to typedef privately here, use a macro.
+// Always take dynamic columns if either side is dynamic.
+# define COLS \
+ ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \
+ ? Eigen::Dynamic \
+ : (ColsLeft + ColsRight))
+
+// Same as above, except that prefer fixed size if either is fixed.
+# define ROWS \
+ ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \
+ ? Eigen::Dynamic \
+ : ((RowsLeft == Eigen::Dynamic) ? RowsRight : RowsLeft))
+
+// TODO(keir): Add a static assert if both rows are at compiletime.
+template <typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+Eigen::Matrix<T, ROWS, COLS> HStack(
+ const Eigen::Matrix<T, RowsLeft, ColsLeft>& left,
+ const Eigen::Matrix<T, RowsRight, ColsRight>& right) {
+ assert(left.rows() == right.rows());
+ int n = left.rows();
+ int m1 = left.cols();
+ int m2 = right.cols();
+
+ Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2);
+ stacked.block(0, 0, n, m1) = left;
+ stacked.block(0, m1, n, m2) = right;
+ return stacked;
+}
+// Reuse the above macros by swapping the order of Rows and Cols. Nasty, but
+// the duplication is worse.
+// TODO(keir): Add a static assert if both rows are at compiletime.
+// TODO(keir): Mail eigen list about making this work for general expressions
+// rather than only matrix types.
+template <typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+Eigen::Matrix<T, COLS, ROWS> VStack(
+ const Eigen::Matrix<T, ColsLeft, RowsLeft>& top,
+ const Eigen::Matrix<T, ColsRight, RowsRight>& bottom) {
+ assert(top.cols() == bottom.cols());
+ int n1 = top.rows();
+ int n2 = bottom.rows();
+ int m = top.cols();
+ Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m);
+ stacked.block(0, 0, n1, m) = top;
+ stacked.block(n1, 0, n2, m) = bottom;
+ return stacked;
+}
+# undef COLS
+# undef ROWS
+#endif // _WIN32
-void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked);
+void HorizontalStack(const Mat& left, const Mat& right, Mat* stacked);
-template<typename TTop, typename TBot, typename TStacked>
-void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) {
+template <typename TTop, typename TBot, typename TStacked>
+void VerticalStack(const TTop& top, const TBot& bottom, TStacked* stacked) {
assert(top.cols() == bottom.cols());
int n1 = top.rows();
int n2 = bottom.rows();
int m = top.cols();
stacked->resize(n1 + n2, m);
- stacked->block(0, 0, n1, m) = top;
+ stacked->block(0, 0, n1, m) = top;
stacked->block(n1, 0, n2, m) = bottom;
}
-void MatrixColumn(const Mat &A, int i, Vec2 *v);
-void MatrixColumn(const Mat &A, int i, Vec3 *v);
-void MatrixColumn(const Mat &A, int i, Vec4 *v);
+void MatrixColumn(const Mat& A, int i, Vec2* v);
+void MatrixColumn(const Mat& A, int i, Vec3* v);
+void MatrixColumn(const Mat& A, int i, Vec4* v);
template <typename TMat, typename TCols>
-TMat ExtractColumns(const TMat &A, const TCols &columns) {
+TMat ExtractColumns(const TMat& A, const TCols& columns) {
TMat compressed(A.rows(), columns.size());
for (int i = 0; i < columns.size(); ++i) {
compressed.col(i) = A.col(columns[i]);
@@ -445,12 +438,12 @@ TMat ExtractColumns(const TMat &A, const TCols &columns) {
}
template <typename TMat, typename TDest>
-void reshape(const TMat &a, int rows, int cols, TDest *b) {
- assert(a.rows()*a.cols() == rows*cols);
+void reshape(const TMat& a, int rows, int cols, TDest* b) {
+ assert(a.rows() * a.cols() == rows * cols);
b->resize(rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
- (*b)(i, j) = a[cols*i + j];
+ (*b)(i, j) = a[cols * i + j];
}
}
}
@@ -467,24 +460,21 @@ inline bool isnan(double i) {
/// and negative values
template <typename FloatType>
FloatType ceil0(const FloatType& value) {
- FloatType result = std::ceil(std::fabs(value));
- return (value < 0.0) ? -result : result;
+ FloatType result = std::ceil(std::fabs(value));
+ return (value < 0.0) ? -result : result;
}
/// Returns the skew anti-symmetric matrix of a vector
-inline Mat3 SkewMat(const Vec3 &x) {
+inline Mat3 SkewMat(const Vec3& x) {
Mat3 skew;
- skew << 0 , -x(2), x(1),
- x(2), 0 , -x(0),
- -x(1), x(0), 0;
+ skew << 0, -x(2), x(1), x(2), 0, -x(0), -x(1), x(0), 0;
return skew;
}
/// Returns the skew anti-symmetric matrix of a vector with only
/// the first two (independent) lines
-inline Mat23 SkewMatMinimal(const Vec2 &x) {
+inline Mat23 SkewMatMinimal(const Vec2& x) {
Mat23 skew;
- skew << 0, -1, x(1),
- 1, 0, -x(0);
+ skew << 0, -1, x(1), 1, 0, -x(0);
return skew;
}
@@ -496,7 +486,8 @@ inline Mat3 RotationFromEulerVector(Vec3 euler_vector) {
}
Vec3 w = euler_vector / theta;
Mat3 w_hat = CrossProductMatrix(w);
- return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta));
+ return Mat3::Identity() + w_hat * sin(theta) +
+ w_hat * w_hat * (1 - cos(theta));
}
} // namespace libmv
diff --git a/intern/libmv/libmv/numeric/numeric_test.cc b/intern/libmv/libmv/numeric/numeric_test.cc
index 0cdfaf33ab2..b2650a04658 100644
--- a/intern/libmv/libmv/numeric/numeric_test.cc
+++ b/intern/libmv/libmv/numeric/numeric_test.cc
@@ -27,9 +27,11 @@ namespace {
TEST(Numeric, DynamicSizedNullspace) {
Mat A(3, 4);
+ // clang-format off
A << 0.76026643, 0.01799744, 0.55192142, 0.8699745,
0.42016166, 0.97863392, 0.33711682, 0.14479271,
0.51016811, 0.66528302, 0.54395496, 0.57794893;
+ // clang-format on
Vec x;
double s = Nullspace(&A, &x);
EXPECT_NEAR(0.0, s, 1e-15);
@@ -39,9 +41,11 @@ TEST(Numeric, DynamicSizedNullspace) {
TEST(Numeric, FixedSizeMatrixNullspace) {
Mat34 A;
+ // clang-format off
A << 0.76026643, 0.01799744, 0.55192142, 0.8699745,
0.42016166, 0.97863392, 0.33711682, 0.14479271,
0.51016811, 0.66528302, 0.54395496, 0.57794893;
+ // clang-format on
Vec x;
double s = Nullspace(&A, &x);
EXPECT_NEAR(0.0, s, 1e-15);
@@ -51,10 +55,12 @@ TEST(Numeric, FixedSizeMatrixNullspace) {
TEST(Numeric, NullspaceMatchesLapackSVD) {
Mat43 A;
+ // clang-format off
A << 0.76026643, 0.01799744, 0.55192142,
0.8699745, 0.42016166, 0.97863392,
0.33711682, 0.14479271, 0.51016811,
0.66528302, 0.54395496, 0.57794893;
+ // clang-format on
Vec x;
double s = Nullspace(&A, &x);
EXPECT_NEAR(1.0, x.norm(), 1e-15);
@@ -68,10 +74,12 @@ TEST(Numeric, NullspaceMatchesLapackSVD) {
TEST(Numeric, Nullspace2) {
Mat43 A;
+ // clang-format off
A << 0.76026643, 0.01799744, 0.55192142,
0.8699745, 0.42016166, 0.97863392,
0.33711682, 0.14479271, 0.51016811,
0.66528302, 0.54395496, 0.57794893;
+ // clang-format on
Vec3 x1, x2;
double s = Nullspace2(&A, &x1, &x2);
EXPECT_NEAR(1.0, x1.norm(), 1e-15);
@@ -80,14 +88,14 @@ TEST(Numeric, Nullspace2) {
EXPECT_NEAR(-0.64999717, x1(0), 1e-8);
EXPECT_NEAR(-0.18452646, x1(1), 1e-8);
- EXPECT_NEAR( 0.7371931, x1(2), 1e-8);
+ EXPECT_NEAR(0.7371931, x1(2), 1e-8);
if (x2(0) < 0) {
x2 *= -1;
}
- EXPECT_NEAR( 0.34679618, x2(0), 1e-8);
+ EXPECT_NEAR(0.34679618, x2(0), 1e-8);
EXPECT_NEAR(-0.93519689, x2(1), 1e-8);
- EXPECT_NEAR( 0.07168809, x2(2), 1e-8);
+ EXPECT_NEAR(0.07168809, x2(2), 1e-8);
}
TEST(Numeric, TinyMatrixSquareTranspose) {
@@ -105,8 +113,8 @@ TEST(Numeric, NormalizeL1) {
x << 1, 2;
double l1 = NormalizeL1(&x);
EXPECT_DOUBLE_EQ(3., l1);
- EXPECT_DOUBLE_EQ(1./3., x(0));
- EXPECT_DOUBLE_EQ(2./3., x(1));
+ EXPECT_DOUBLE_EQ(1. / 3., x(0));
+ EXPECT_DOUBLE_EQ(2. / 3., x(1));
}
TEST(Numeric, NormalizeL2) {
@@ -114,8 +122,8 @@ TEST(Numeric, NormalizeL2) {
x << 1, 2;
double l2 = NormalizeL2(&x);
EXPECT_DOUBLE_EQ(sqrt(5.0), l2);
- EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0));
- EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1));
+ EXPECT_DOUBLE_EQ(1. / sqrt(5.), x(0));
+ EXPECT_DOUBLE_EQ(2. / sqrt(5.), x(1));
}
TEST(Numeric, Diag) {
@@ -130,31 +138,32 @@ TEST(Numeric, Diag) {
TEST(Numeric, Determinant) {
Mat A(2, 2);
- A << 1, 2,
- -1, 3;
+ A << 1, 2, -1, 3;
double detA = A.determinant();
EXPECT_NEAR(5, detA, 1e-8);
Mat B(4, 4);
+ // clang-format off
B << 0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15;
+ // clang-format on
double detB = B.determinant();
EXPECT_NEAR(0, detB, 1e-8);
Mat3 C;
- C << 0, 1, 2,
- 3, 4, 5,
- 6, 7, 1;
+ C << 0, 1, 2, 3, 4, 5, 6, 7, 1;
double detC = C.determinant();
EXPECT_NEAR(21, detC, 1e-8);
}
TEST(Numeric, Inverse) {
Mat A(2, 2), A1;
+ // clang-format off
A << 1, 2,
-1, 3;
+ // clang-format on
Mat I = A * A.inverse();
EXPECT_NEAR(1, I(0, 0), 1e-8);
@@ -163,10 +172,12 @@ TEST(Numeric, Inverse) {
EXPECT_NEAR(1, I(1, 1), 1e-8);
Mat B(4, 4), B1;
+ // clang-format off
B << 0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 2, 11,
12, 13, 14, 4;
+ // clang-format on
Mat I2 = B * B.inverse();
EXPECT_NEAR(1, I2(0, 0), 1e-8);
EXPECT_NEAR(0, I2(0, 1), 1e-8);
@@ -182,8 +193,10 @@ TEST(Numeric, Inverse) {
TEST(Numeric, MeanAndVarianceAlongRows) {
int n = 4;
Mat points(2, n);
+ // clang-format off
points << 0, 0, 1, 1,
0, 2, 1, 3;
+ // clang-format on
Vec mean, variance;
MeanAndVarianceAlongRows(points, &mean, &variance);
@@ -213,15 +226,17 @@ TEST(Numeric, HStack) {
Mat x(2, 1), y(2, 1), z(2, 2);
x << 1, 2;
y << 3, 4;
+ // clang-format off
z << 1, 3,
2, 4;
+ // clang-format on
Vec2 xC = x, yC = y;
- Mat2 xy = HStack(x, y);
+ Mat2 xy = HStack(x, y);
EXPECT_MATRIX_EQ(z, xy);
- EXPECT_MATRIX_EQ(z, HStack(x, y));
- EXPECT_MATRIX_EQ(z, HStack(x, yC));
+ EXPECT_MATRIX_EQ(z, HStack(x, y));
+ EXPECT_MATRIX_EQ(z, HStack(x, yC));
EXPECT_MATRIX_EQ(z, HStack(xC, y));
EXPECT_MATRIX_EQ(z, HStack(xC, yC));
}
@@ -230,6 +245,7 @@ TEST(Numeric, HStack) {
// resulting stacked matrices properly propagate the fixed dimensions.
TEST(Numeric, VStack) {
Mat x(2, 2), y(2, 2), z(4, 2);
+ // clang-format off
x << 1, 2,
3, 4;
y << 10, 20,
@@ -238,13 +254,14 @@ TEST(Numeric, VStack) {
3, 4,
10, 20,
30, 40;
+ // clang-format on
Mat2 xC = x, yC = y;
- Mat xy = VStack(x, y);
+ Mat xy = VStack(x, y);
EXPECT_MATRIX_EQ(z, xy);
- EXPECT_MATRIX_EQ(z, VStack(x, y));
- EXPECT_MATRIX_EQ(z, VStack(x, yC));
+ EXPECT_MATRIX_EQ(z, VStack(x, y));
+ EXPECT_MATRIX_EQ(z, VStack(x, yC));
EXPECT_MATRIX_EQ(z, VStack(xC, y));
EXPECT_MATRIX_EQ(z, VStack(xC, yC));
}
@@ -293,17 +310,21 @@ TEST(Numeric, CrossProductMatrix) {
TEST(Numeric, MatrixColumn) {
Mat A2(2, 3);
Vec2 v2;
+ // clang-format off
A2 << 1, 2, 3,
4, 5, 6;
+ // clang-format on
MatrixColumn(A2, 1, &v2);
EXPECT_EQ(2, v2(0));
EXPECT_EQ(5, v2(1));
Mat A3(3, 3);
Vec3 v3;
+ // clang-format off
A3 << 1, 2, 3,
4, 5, 6,
7, 8, 9;
+ // clang-format on
MatrixColumn(A3, 1, &v3);
EXPECT_EQ(2, v3(0));
EXPECT_EQ(5, v3(1));
@@ -311,14 +332,16 @@ TEST(Numeric, MatrixColumn) {
Mat A4(4, 3);
Vec4 v4;
+ // clang-format off
A4 << 1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12;
+ // clang-format on
MatrixColumn(A4, 1, &v4);
- EXPECT_EQ( 2, v4(0));
- EXPECT_EQ( 5, v4(1));
- EXPECT_EQ( 8, v4(2));
+ EXPECT_EQ(2, v4(0));
+ EXPECT_EQ(5, v4(1));
+ EXPECT_EQ(8, v4(2));
EXPECT_EQ(11, v4(3));
}
@@ -337,7 +360,8 @@ TEST(Numeric, Mat3MatProduct) {
// This gives a compile error.
TEST(Numeric, Vec3Negative) {
- Vec3 y; y << 1, 2, 3;
+ Vec3 y;
+ y << 1, 2, 3;
Vec3 x = -y;
EXPECT_EQ(-1, x(0));
EXPECT_EQ(-2, x(1));
@@ -357,19 +381,23 @@ TEST(Numeric, Vec3VecInteroperability) {
// This segfaults inside lapack.
TEST(Numeric, DeterminantLU7) {
Mat A(5, 5);
+ // clang-format off
A << 1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1;
+ // clang-format on
EXPECT_NEAR(1, A.determinant(), 1e-8);
}
// This segfaults inside lapack.
TEST(Numeric, DeterminantLU) {
Mat A(2, 2);
+ // clang-format off
A << 1, 2,
-1, 3;
+ // clang-format on
EXPECT_NEAR(5, A.determinant(), 1e-8);
}
@@ -377,19 +405,24 @@ TEST(Numeric, DeterminantLU) {
// Keir: Not with eigen2!
TEST(Numeric, InplaceProduct) {
Mat2 K, S;
+ // clang-format off
K << 1, 0,
0, 1;
S << 1, 0,
0, 1;
K = K * S;
+ // clang-format on
EXPECT_MATRIX_NEAR(Mat2::Identity(), K, 1e-8);
}
TEST(Numeric, ExtractColumns) {
Mat2X A(2, 5);
+ // clang-format off
A << 1, 2, 3, 4, 5,
6, 7, 8, 9, 10;
- Vec2i columns; columns << 0, 2;
+ // clang-format on
+ Vec2i columns;
+ columns << 0, 2;
Mat2X extracted = ExtractColumns(A, columns);
EXPECT_NEAR(1, extracted(0, 0), 1e-15);
EXPECT_NEAR(3, extracted(0, 1), 1e-15);
@@ -418,21 +451,22 @@ TEST(Numeric, RotationRodrigues) {
TEST(Numeric, LookAt) {
// Simple orthogonality check.
- Vec3 e; e << 1, 2, 3;
+ Vec3 e;
+ e << 1, 2, 3;
Mat3 R = LookAt(e), I = Mat3::Identity();
- Mat3 RRT = R*R.transpose();
- Mat3 RTR = R.transpose()*R;
+ Mat3 RRT = R * R.transpose();
+ Mat3 RTR = R.transpose() * R;
EXPECT_MATRIX_NEAR(I, RRT, 1e-15);
EXPECT_MATRIX_NEAR(I, RTR, 1e-15);
}
TEST(Numeric, Reshape) {
- Vec4 x; x << 1, 2, 3, 4;
+ Vec4 x;
+ x << 1, 2, 3, 4;
Mat2 M, M_expected;
reshape(x, 2, 2, &M);
- M_expected << 1, 2,
- 3, 4;
+ M_expected << 1, 2, 3, 4;
EXPECT_MATRIX_NEAR(M_expected, M, 1e-15);
}
diff --git a/intern/libmv/libmv/numeric/poly.h b/intern/libmv/libmv/numeric/poly.h
index 76ba062d475..a3d3801a399 100644
--- a/intern/libmv/libmv/numeric/poly.h
+++ b/intern/libmv/libmv/numeric/poly.h
@@ -21,8 +21,8 @@
#ifndef LIBMV_NUMERIC_POLY_H_
#define LIBMV_NUMERIC_POLY_H_
-#include <cmath>
#include <stdio.h>
+#include <cmath>
namespace libmv {
@@ -35,9 +35,8 @@ namespace libmv {
// if there are 2 roots, only x0 and x1 are set.
//
// The GSL cubic solver was used as a reference for this routine.
-template<typename Real>
-int SolveCubicPolynomial(Real a, Real b, Real c,
- Real *x0, Real *x1, Real *x2) {
+template <typename Real>
+int SolveCubicPolynomial(Real a, Real b, Real c, Real* x0, Real* x1, Real* x2) {
Real q = a * a - 3 * b;
Real r = 2 * a * a * a - 9 * a * b + 27 * c;
@@ -65,12 +64,12 @@ int SolveCubicPolynomial(Real a, Real b, Real c,
Real sqrtQ = sqrt(Q);
if (R > 0) {
*x0 = -2 * sqrtQ - a / 3;
- *x1 = sqrtQ - a / 3;
- *x2 = sqrtQ - a / 3;
+ *x1 = sqrtQ - a / 3;
+ *x2 = sqrtQ - a / 3;
} else {
- *x0 = -sqrtQ - a / 3;
- *x1 = -sqrtQ - a / 3;
- *x2 = 2 * sqrtQ - a / 3;
+ *x0 = -sqrtQ - a / 3;
+ *x1 = -sqrtQ - a / 3;
+ *x2 = 2 * sqrtQ - a / 3;
}
return 3;
@@ -97,15 +96,15 @@ int SolveCubicPolynomial(Real a, Real b, Real c,
return 3;
}
Real sgnR = (R >= 0 ? 1 : -1);
- Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0/3.0);
+ Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0 / 3.0);
Real B = Q / A;
*x0 = A + B - a / 3;
return 1;
}
// The coefficients are in ascending powers, i.e. coeffs[N]*x^N.
-template<typename Real>
-int SolveCubicPolynomial(const Real *coeffs, Real *solutions) {
+template <typename Real>
+int SolveCubicPolynomial(const Real* coeffs, Real* solutions) {
if (coeffs[0] == 0.0) {
// TODO(keir): This is a quadratic not a cubic. Implement a quadratic
// solver!
@@ -114,10 +113,8 @@ int SolveCubicPolynomial(const Real *coeffs, Real *solutions) {
Real a = coeffs[2] / coeffs[3];
Real b = coeffs[1] / coeffs[3];
Real c = coeffs[0] / coeffs[3];
- return SolveCubicPolynomial(a, b, c,
- solutions + 0,
- solutions + 1,
- solutions + 2);
+ return SolveCubicPolynomial(
+ a, b, c, solutions + 0, solutions + 1, solutions + 2);
}
} // namespace libmv
#endif // LIBMV_NUMERIC_POLY_H_
diff --git a/intern/libmv/libmv/numeric/poly_test.cc b/intern/libmv/libmv/numeric/poly_test.cc
index 69f887b416c..cb85c068468 100644
--- a/intern/libmv/libmv/numeric/poly_test.cc
+++ b/intern/libmv/libmv/numeric/poly_test.cc
@@ -18,8 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#include "libmv/numeric/numeric.h"
#include "libmv/numeric/poly.h"
+#include "libmv/numeric/numeric.h"
#include "testing/testing.h"
using namespace libmv;
@@ -34,8 +34,8 @@ namespace {
//
// x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0.
// = p = q = r
-void CoeffsForCubicZeros(double a, double b, double c,
- double *p, double *q, double *r) {
+void CoeffsForCubicZeros(
+ double a, double b, double c, double* p, double* q, double* r) {
*p = -(c + b + a);
*q = (a * b + (b + a) * c);
*r = -a * b * c;
@@ -45,35 +45,45 @@ TEST(Poly, SolveCubicPolynomial) {
double a, b, c, aa, bb, cc;
double p, q, r;
- a = 1; b = 2; c = 3;
+ a = 1;
+ b = 2;
+ c = 3;
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
EXPECT_NEAR(a, aa, 1e-10);
EXPECT_NEAR(b, bb, 1e-10);
EXPECT_NEAR(c, cc, 1e-10);
- a = 0; b = 1; c = 3;
+ a = 0;
+ b = 1;
+ c = 3;
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
EXPECT_NEAR(a, aa, 1e-10);
EXPECT_NEAR(b, bb, 1e-10);
EXPECT_NEAR(c, cc, 1e-10);
- a = -10; b = 0; c = 1;
+ a = -10;
+ b = 0;
+ c = 1;
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
EXPECT_NEAR(a, aa, 1e-10);
EXPECT_NEAR(b, bb, 1e-10);
EXPECT_NEAR(c, cc, 1e-10);
- a = -8; b = 1; c = 3;
+ a = -8;
+ b = 1;
+ c = 3;
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
EXPECT_NEAR(a, aa, 1e-10);
EXPECT_NEAR(b, bb, 1e-10);
EXPECT_NEAR(c, cc, 1e-10);
- a = 28; b = 28; c = 105;
+ a = 28;
+ b = 28;
+ c = 105;
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
EXPECT_NEAR(a, aa, 1e-10);
diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc
index 25a63c87e1b..e86c3bca57f 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
@@ -32,16 +32,16 @@
#include "libmv/multiview/projection.h"
#include "libmv/numeric/numeric.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
-#include "libmv/simple_pipeline/reconstruction.h"
-#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/distortion_models.h"
#include "libmv/simple_pipeline/packed_intrinsics.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
namespace {
-bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) {
+bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics* intrinsics) {
const DistortionModelType distortion_model =
intrinsics->GetDistortionModelType();
return (distortion_model == DISTORTION_MODEL_NUKE);
@@ -59,12 +59,14 @@ bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) {
// The invariant_intrinsics are used to access intrinsics which are never
// packed into parameter block: for example, distortion model type and image
// dimension.
-template<typename T>
+template <typename T>
void ApplyDistortionModelUsingIntrinsicsBlock(
- const CameraIntrinsics *invariant_intrinsics,
+ const CameraIntrinsics* invariant_intrinsics,
const T* const intrinsics_block,
- const T& normalized_x, const T& normalized_y,
- T* distorted_x, T* distorted_y) {
+ const T& normalized_x,
+ const T& normalized_y,
+ T* distorted_x,
+ T* distorted_y) {
// Unpack the intrinsics.
const T& focal_length =
intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH];
@@ -76,65 +78,75 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
// TODO(keir): Do early bailouts for zero distortion; these are expensive
// jet operations.
switch (invariant_intrinsics->GetDistortionModelType()) {
- case DISTORTION_MODEL_POLYNOMIAL:
- {
- const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
- const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
- const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3];
- const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1];
- const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2];
-
- ApplyPolynomialDistortionModel(focal_length,
- focal_length,
- principal_point_x,
- principal_point_y,
- k1, k2, k3,
- p1, p2,
- normalized_x, normalized_y,
- distorted_x, distorted_y);
- return;
- }
-
- case DISTORTION_MODEL_DIVISION:
- {
- const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
- const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
-
- ApplyDivisionDistortionModel(focal_length,
+ case DISTORTION_MODEL_POLYNOMIAL: {
+ const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
+ const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
+ const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3];
+ const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1];
+ const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2];
+
+ ApplyPolynomialDistortionModel(focal_length,
focal_length,
principal_point_x,
principal_point_y,
- k1, k2,
- normalized_x, normalized_y,
- distorted_x, distorted_y);
- return;
- }
+ k1,
+ k2,
+ k3,
+ p1,
+ p2,
+ normalized_x,
+ normalized_y,
+ distorted_x,
+ distorted_y);
+ return;
+ }
- case DISTORTION_MODEL_NUKE:
- {
- LOG(FATAL) << "Unsupported distortion model.";
- return;
- }
+ case DISTORTION_MODEL_DIVISION: {
+ const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
+ const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
+
+ ApplyDivisionDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1,
+ k2,
+ normalized_x,
+ normalized_y,
+ distorted_x,
+ distorted_y);
+ return;
+ }
- case DISTORTION_MODEL_BROWN:
- {
- const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
- const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
- const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3];
- const T& k4 = intrinsics_block[PackedIntrinsics::OFFSET_K4];
- const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1];
- const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2];
-
- ApplyBrownDistortionModel(focal_length,
- focal_length,
- principal_point_x,
- principal_point_y,
- k1, k2, k3, k4,
- p1, p2,
- normalized_x, normalized_y,
- distorted_x, distorted_y);
- return;
- }
+ case DISTORTION_MODEL_NUKE: {
+ LOG(FATAL) << "Unsupported distortion model.";
+ return;
+ }
+
+ case DISTORTION_MODEL_BROWN: {
+ const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
+ const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
+ const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3];
+ const T& k4 = intrinsics_block[PackedIntrinsics::OFFSET_K4];
+ const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1];
+ const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2];
+
+ ApplyBrownDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1,
+ k2,
+ k3,
+ k4,
+ p1,
+ p2,
+ normalized_x,
+ normalized_y,
+ distorted_x,
+ distorted_y);
+ return;
+ }
}
LOG(FATAL) << "Unknown distortion model.";
@@ -152,12 +164,14 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
// The invariant_intrinsics are used to access intrinsics which are never
// packed into parameter block: for example, distortion model type and image
// dimension.
-template<typename T>
+template <typename T>
void InvertDistortionModelUsingIntrinsicsBlock(
- const CameraIntrinsics *invariant_intrinsics,
+ const CameraIntrinsics* invariant_intrinsics,
const T* const intrinsics_block,
- const T& image_x, const T& image_y,
- T* normalized_x, T* normalized_y) {
+ const T& image_x,
+ const T& image_y,
+ T* normalized_x,
+ T* normalized_y) {
// Unpack the intrinsics.
const T& focal_length =
intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH];
@@ -175,31 +189,35 @@ void InvertDistortionModelUsingIntrinsicsBlock(
LOG(FATAL) << "Unsupported distortion model.";
return;
- case DISTORTION_MODEL_NUKE:
- {
- const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
- const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
-
- InvertNukeDistortionModel(focal_length,
- focal_length,
- principal_point_x,
- principal_point_y,
- invariant_intrinsics->image_width(),
- invariant_intrinsics->image_height(),
- k1, k2,
- image_x, image_y,
- normalized_x, normalized_y);
- return;
- }
+ case DISTORTION_MODEL_NUKE: {
+ const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1];
+ const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2];
+
+ InvertNukeDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ invariant_intrinsics->image_width(),
+ invariant_intrinsics->image_height(),
+ k1,
+ k2,
+ image_x,
+ image_y,
+ normalized_x,
+ normalized_y);
+ return;
+ }
}
LOG(FATAL) << "Unknown distortion model.";
}
-template<typename T>
+template <typename T>
void NormalizedToImageSpace(const T* const intrinsics_block,
- const T& normalized_x, const T& normalized_y,
- T* image_x, T* image_y) {
+ const T& normalized_x,
+ const T& normalized_y,
+ T* image_x,
+ T* image_y) {
// Unpack the intrinsics.
const T& focal_length =
intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH];
@@ -219,11 +237,10 @@ void NormalizedToImageSpace(const T* const intrinsics_block,
// This functor can only be used for distortion models which have analytically
// defined Apply() function.
struct ReprojectionErrorApplyIntrinsics {
- ReprojectionErrorApplyIntrinsics(
- const CameraIntrinsics *invariant_intrinsics,
- const double observed_distorted_x,
- const double observed_distorted_y,
- const double weight)
+ ReprojectionErrorApplyIntrinsics(const CameraIntrinsics* invariant_intrinsics,
+ const double observed_distorted_x,
+ const double observed_distorted_y,
+ const double weight)
: invariant_intrinsics_(invariant_intrinsics),
observed_distorted_x_(observed_distorted_x),
observed_distorted_y_(observed_distorted_y),
@@ -253,11 +270,12 @@ struct ReprojectionErrorApplyIntrinsics {
T yn = x[1] / x[2];
T predicted_distorted_x, predicted_distorted_y;
- ApplyDistortionModelUsingIntrinsicsBlock(
- invariant_intrinsics_,
- intrinsics,
- xn, yn,
- &predicted_distorted_x, &predicted_distorted_y);
+ ApplyDistortionModelUsingIntrinsicsBlock(invariant_intrinsics_,
+ intrinsics,
+ xn,
+ yn,
+ &predicted_distorted_x,
+ &predicted_distorted_y);
// The error is the difference between the predicted and observed position.
residuals[0] = (predicted_distorted_x - T(observed_distorted_x_)) * weight_;
@@ -265,7 +283,7 @@ struct ReprojectionErrorApplyIntrinsics {
return true;
}
- const CameraIntrinsics *invariant_intrinsics_;
+ const CameraIntrinsics* invariant_intrinsics_;
const double observed_distorted_x_;
const double observed_distorted_y_;
const double weight_;
@@ -279,7 +297,7 @@ struct ReprojectionErrorApplyIntrinsics {
// defined Invert() function.
struct ReprojectionErrorInvertIntrinsics {
ReprojectionErrorInvertIntrinsics(
- const CameraIntrinsics *invariant_intrinsics,
+ const CameraIntrinsics* invariant_intrinsics,
const double observed_distorted_x,
const double observed_distorted_y,
const double weight)
@@ -295,8 +313,7 @@ struct ReprojectionErrorInvertIntrinsics {
const T* const X, // Point coordinates 3x1.
T* residuals) const {
// Unpack the intrinsics.
- const T& focal_length =
- intrinsics[PackedIntrinsics::OFFSET_FOCAL_LENGTH];
+ const T& focal_length = intrinsics[PackedIntrinsics::OFFSET_FOCAL_LENGTH];
const T& principal_point_x =
intrinsics[PackedIntrinsics::OFFSET_PRINCIPAL_POINT_X];
const T& principal_point_y =
@@ -327,14 +344,17 @@ struct ReprojectionErrorInvertIntrinsics {
InvertDistortionModelUsingIntrinsicsBlock(
invariant_intrinsics_,
intrinsics,
- T(observed_distorted_x_), T(observed_distorted_y_),
- &observed_undistorted_normalized_x, &observed_undistorted_normalized_y);
+ T(observed_distorted_x_),
+ T(observed_distorted_y_),
+ &observed_undistorted_normalized_x,
+ &observed_undistorted_normalized_y);
T observed_undistorted_image_x, observed_undistorted_image_y;
- NormalizedToImageSpace(
- intrinsics,
- observed_undistorted_normalized_x, observed_undistorted_normalized_y,
- &observed_undistorted_image_x, &observed_undistorted_image_y);
+ NormalizedToImageSpace(intrinsics,
+ observed_undistorted_normalized_x,
+ observed_undistorted_normalized_y,
+ &observed_undistorted_image_x,
+ &observed_undistorted_image_y);
// The error is the difference between the predicted and observed position.
residuals[0] = (predicted_x - observed_undistorted_image_x) * weight_;
@@ -343,7 +363,7 @@ struct ReprojectionErrorInvertIntrinsics {
return true;
}
- const CameraIntrinsics *invariant_intrinsics_;
+ const CameraIntrinsics* invariant_intrinsics_;
const double observed_distorted_x_;
const double observed_distorted_y_;
const double weight_;
@@ -356,22 +376,23 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
} else {
std::string bundling_message = "";
-#define APPEND_BUNDLING_INTRINSICS(name, flag) \
- if (bundle_intrinsics & flag) { \
- if (!bundling_message.empty()) { \
- bundling_message += ", "; \
- } \
- bundling_message += name; \
- } (void)0
+#define APPEND_BUNDLING_INTRINSICS(name, flag) \
+ if (bundle_intrinsics & flag) { \
+ if (!bundling_message.empty()) { \
+ bundling_message += ", "; \
+ } \
+ bundling_message += name; \
+ } \
+ (void)0
- APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH);
+ APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH);
APPEND_BUNDLING_INTRINSICS("px, py", BUNDLE_PRINCIPAL_POINT);
- APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1);
- APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2);
- APPEND_BUNDLING_INTRINSICS("k3", BUNDLE_RADIAL_K3);
- APPEND_BUNDLING_INTRINSICS("k4", BUNDLE_RADIAL_K4);
- APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1);
- APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2);
+ APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1);
+ APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2);
+ APPEND_BUNDLING_INTRINSICS("k3", BUNDLE_RADIAL_K3);
+ APPEND_BUNDLING_INTRINSICS("k4", BUNDLE_RADIAL_K4);
+ APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1);
+ APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2);
LG << "Bundling " << bundling_message << ".";
}
@@ -383,7 +404,7 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
// Element with key i matches to a rotation+translation for
// camera at image i.
map<int, Vec6> PackCamerasRotationAndTranslation(
- const EuclideanReconstruction &reconstruction) {
+ const EuclideanReconstruction& reconstruction) {
map<int, Vec6> all_cameras_R_t;
vector<EuclideanCamera> all_cameras = reconstruction.AllCameras();
@@ -399,14 +420,13 @@ map<int, Vec6> PackCamerasRotationAndTranslation(
// Convert cameras rotations fro mangle axis back to rotation matrix.
void UnpackCamerasRotationAndTranslation(
- const map<int, Vec6> &all_cameras_R_t,
- EuclideanReconstruction *reconstruction) {
-
+ const map<int, Vec6>& all_cameras_R_t,
+ EuclideanReconstruction* reconstruction) {
for (map<int, Vec6>::value_type image_and_camera_R_T : all_cameras_R_t) {
const int image = image_and_camera_R_T.first;
const Vec6& camera_R_t = image_and_camera_R_T.second;
- EuclideanCamera *camera = reconstruction->CameraForImage(image);
+ EuclideanCamera* camera = reconstruction->CameraForImage(image);
if (!camera) {
continue;
}
@@ -421,8 +441,8 @@ void UnpackCamerasRotationAndTranslation(
//
// TODO(sergey): currently uses dense Eigen matrices, best would
// be to use sparse Eigen matrices
-void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix,
- Mat *eigen_matrix) {
+void CRSMatrixToEigenMatrix(const ceres::CRSMatrix& crs_matrix,
+ Mat* eigen_matrix) {
eigen_matrix->resize(crs_matrix.num_rows, crs_matrix.num_cols);
eigen_matrix->setZero();
@@ -439,11 +459,11 @@ void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix,
}
}
-void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
- EuclideanReconstruction *reconstruction,
- map<int, Vec6> *all_cameras_R_t,
- ceres::Problem *problem,
- BundleEvaluation *evaluation) {
+void EuclideanBundlerPerformEvaluation(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction,
+ map<int, Vec6>* all_cameras_R_t,
+ ceres::Problem* problem,
+ BundleEvaluation* evaluation) {
int max_track = tracks.MaxTrack();
// Number of camera rotations equals to number of translation,
int num_cameras = all_cameras_R_t->size();
@@ -451,7 +471,7 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
vector<EuclideanPoint*> minimized_points;
for (int i = 0; i <= max_track; i++) {
- EuclideanPoint *point = reconstruction->PointForTrack(i);
+ EuclideanPoint* point = reconstruction->PointForTrack(i);
if (point) {
// We need to know whether the track is a constant zero weight.
// If it is so it wouldn't have a parameter block in the problem.
@@ -477,16 +497,16 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
evaluation->num_cameras = num_cameras;
evaluation->num_points = num_points;
- if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix.
+ if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix.
ceres::CRSMatrix evaluated_jacobian;
ceres::Problem::EvaluateOptions eval_options;
// Cameras goes first in the ordering.
int max_image = tracks.MaxImage();
for (int i = 0; i <= max_image; i++) {
- const EuclideanCamera *camera = reconstruction->CameraForImage(i);
+ const EuclideanCamera* camera = reconstruction->CameraForImage(i);
if (camera) {
- double *current_camera_R_t = &(*all_cameras_R_t)[i](0);
+ double* current_camera_R_t = &(*all_cameras_R_t)[i](0);
// All cameras are variable now.
problem->SetParameterBlockVariable(current_camera_R_t);
@@ -497,63 +517,65 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
// Points goes at the end of ordering,
for (int i = 0; i < minimized_points.size(); i++) {
- EuclideanPoint *point = minimized_points.at(i);
+ EuclideanPoint* point = minimized_points.at(i);
eval_options.parameter_blocks.push_back(&point->X(0));
}
- problem->Evaluate(eval_options,
- NULL, NULL, NULL,
- &evaluated_jacobian);
+ problem->Evaluate(eval_options, NULL, NULL, NULL, &evaluated_jacobian);
CRSMatrixToEigenMatrix(evaluated_jacobian, &evaluation->jacobian);
}
}
-template<typename CostFunction>
-void AddResidualBlockToProblemImpl(const CameraIntrinsics *invariant_intrinsics,
- double observed_x, double observed_y,
+template <typename CostFunction>
+void AddResidualBlockToProblemImpl(const CameraIntrinsics* invariant_intrinsics,
+ double observed_x,
+ double observed_y,
double weight,
- double *intrinsics_block,
- double *camera_R_t,
- EuclideanPoint *point,
+ double* intrinsics_block,
+ double* camera_R_t,
+ EuclideanPoint* point,
ceres::Problem* problem) {
- problem->AddResidualBlock(new ceres::AutoDiffCostFunction<
- CostFunction, 2, PackedIntrinsics::NUM_PARAMETERS, 6, 3>(
- new CostFunction(
- invariant_intrinsics,
- observed_x, observed_y,
- weight)),
+ problem->AddResidualBlock(
+ new ceres::AutoDiffCostFunction<CostFunction,
+ 2,
+ PackedIntrinsics::NUM_PARAMETERS,
+ 6,
+ 3>(new CostFunction(
+ invariant_intrinsics, observed_x, observed_y, weight)),
NULL,
intrinsics_block,
camera_R_t,
&point->X(0));
}
-void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics,
- const Marker &marker,
+void AddResidualBlockToProblem(const CameraIntrinsics* invariant_intrinsics,
+ const Marker& marker,
double marker_weight,
double* intrinsics_block,
- double *camera_R_t,
- EuclideanPoint *point,
+ double* camera_R_t,
+ EuclideanPoint* point,
ceres::Problem* problem) {
if (NeedUseInvertIntrinsicsPipeline(invariant_intrinsics)) {
AddResidualBlockToProblemImpl<ReprojectionErrorInvertIntrinsics>(
- invariant_intrinsics,
- marker.x, marker.y,
- marker_weight,
- intrinsics_block,
- camera_R_t,
- point,
- problem);
+ invariant_intrinsics,
+ marker.x,
+ marker.y,
+ marker_weight,
+ intrinsics_block,
+ camera_R_t,
+ point,
+ problem);
} else {
AddResidualBlockToProblemImpl<ReprojectionErrorApplyIntrinsics>(
- invariant_intrinsics,
- marker.x, marker.y,
- marker_weight,
- intrinsics_block,
- camera_R_t,
- point,
- problem);
+ invariant_intrinsics,
+ marker.x,
+ marker.y,
+ marker_weight,
+ intrinsics_block,
+ camera_R_t,
+ point,
+ problem);
}
}
@@ -566,25 +588,25 @@ void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics,
//
// At this point we only need to bundle points positions, cameras
// are to be totally still here.
-void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics,
- const vector<Marker> &markers,
- map<int, Vec6> &all_cameras_R_t,
+void EuclideanBundlePointsOnly(const CameraIntrinsics* invariant_intrinsics,
+ const vector<Marker>& markers,
+ map<int, Vec6>& all_cameras_R_t,
double* intrinsics_block,
- EuclideanReconstruction *reconstruction) {
+ EuclideanReconstruction* reconstruction) {
ceres::Problem::Options problem_options;
ceres::Problem problem(problem_options);
int num_residuals = 0;
for (int i = 0; i < markers.size(); ++i) {
- const Marker &marker = markers[i];
- EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ const Marker& marker = markers[i];
+ EuclideanCamera* camera = reconstruction->CameraForImage(marker.image);
+ EuclideanPoint* point = reconstruction->PointForTrack(marker.track);
if (camera == NULL || point == NULL) {
continue;
}
// Rotation of camera denoted in angle axis followed with
// camera translation.
- double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
+ double* current_camera_R_t = &all_cameras_R_t[camera->image](0);
AddResidualBlockToProblem(invariant_intrinsics,
marker,
@@ -625,8 +647,8 @@ void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics,
} // namespace
-void EuclideanBundle(const Tracks &tracks,
- EuclideanReconstruction *reconstruction) {
+void EuclideanBundle(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction) {
PolynomialCameraIntrinsics empty_intrinsics;
EuclideanBundleCommonIntrinsics(tracks,
BUNDLE_NO_INTRINSICS,
@@ -636,13 +658,12 @@ void EuclideanBundle(const Tracks &tracks,
NULL);
}
-void EuclideanBundleCommonIntrinsics(
- const Tracks &tracks,
- const int bundle_intrinsics,
- const int bundle_constraints,
- EuclideanReconstruction *reconstruction,
- CameraIntrinsics *intrinsics,
- BundleEvaluation *evaluation) {
+void EuclideanBundleCommonIntrinsics(const Tracks& tracks,
+ const int bundle_intrinsics,
+ const int bundle_constraints,
+ EuclideanReconstruction* reconstruction,
+ CameraIntrinsics* intrinsics,
+ BundleEvaluation* evaluation) {
LG << "Original intrinsics: " << *intrinsics;
vector<Marker> markers = tracks.AllMarkers();
@@ -661,19 +682,19 @@ void EuclideanBundleCommonIntrinsics(
// Block for minimization has got the following structure:
// <3 elements for angle-axis> <3 elements for translation>
map<int, Vec6> all_cameras_R_t =
- PackCamerasRotationAndTranslation(*reconstruction);
+ PackCamerasRotationAndTranslation(*reconstruction);
// Parameterization used to restrict camera motion for modal solvers.
- ceres::SubsetParameterization *constant_translation_parameterization = NULL;
+ ceres::SubsetParameterization* constant_translation_parameterization = NULL;
if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
- std::vector<int> constant_translation;
+ std::vector<int> constant_translation;
- // First three elements are rotation, ast three are translation.
- constant_translation.push_back(3);
- constant_translation.push_back(4);
- constant_translation.push_back(5);
+ // First three elements are rotation, ast three are translation.
+ constant_translation.push_back(3);
+ constant_translation.push_back(4);
+ constant_translation.push_back(5);
- constant_translation_parameterization =
+ constant_translation_parameterization =
new ceres::SubsetParameterization(6, constant_translation);
}
@@ -683,16 +704,16 @@ void EuclideanBundleCommonIntrinsics(
int num_residuals = 0;
bool have_locked_camera = false;
for (int i = 0; i < markers.size(); ++i) {
- const Marker &marker = markers[i];
- EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ const Marker& marker = markers[i];
+ EuclideanCamera* camera = reconstruction->CameraForImage(marker.image);
+ EuclideanPoint* point = reconstruction->PointForTrack(marker.track);
if (camera == NULL || point == NULL) {
continue;
}
// Rotation of camera denoted in angle axis followed with
// camera translation.
- double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
+ double* current_camera_R_t = &all_cameras_R_t[camera->image](0);
// Skip residual block for markers which does have absolutely
// no affect on the final solution.
@@ -706,7 +727,8 @@ void EuclideanBundleCommonIntrinsics(
point,
&problem);
- // We lock the first camera to better deal with scene orientation ambiguity.
+ // We lock the first camera to better deal with scene orientation
+ // ambiguity.
if (!have_locked_camera) {
problem.SetParameterBlockConstant(current_camera_R_t);
have_locked_camera = true;
@@ -729,7 +751,7 @@ void EuclideanBundleCommonIntrinsics(
}
if (intrinsics->GetDistortionModelType() == DISTORTION_MODEL_DIVISION &&
- (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) {
+ (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) {
LOG(FATAL) << "Division model doesn't support bundling "
"of tangential distortion";
}
@@ -745,29 +767,29 @@ void EuclideanBundleCommonIntrinsics(
// constant using some macro trickery.
std::vector<int> constant_intrinsics;
-#define MAYBE_SET_CONSTANT(bundle_enum, offset) \
- if (!(bundle_intrinsics & bundle_enum) || \
- !packed_intrinsics.IsParameterDefined(offset)) { \
- constant_intrinsics.push_back(offset); \
- }
+#define MAYBE_SET_CONSTANT(bundle_enum, offset) \
+ if (!(bundle_intrinsics & bundle_enum) || \
+ !packed_intrinsics.IsParameterDefined(offset)) { \
+ constant_intrinsics.push_back(offset); \
+ }
MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH,
PackedIntrinsics::OFFSET_FOCAL_LENGTH);
MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT,
PackedIntrinsics::OFFSET_PRINCIPAL_POINT_X);
MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT,
PackedIntrinsics::OFFSET_PRINCIPAL_POINT_Y);
- MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, PackedIntrinsics::OFFSET_K1);
- MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, PackedIntrinsics::OFFSET_K2);
- MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K3, PackedIntrinsics::OFFSET_K3);
- MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K4, PackedIntrinsics::OFFSET_K4);
- MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, PackedIntrinsics::OFFSET_P1);
- MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, PackedIntrinsics::OFFSET_P2);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, PackedIntrinsics::OFFSET_K1);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, PackedIntrinsics::OFFSET_K2);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K3, PackedIntrinsics::OFFSET_K3);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K4, PackedIntrinsics::OFFSET_K4);
+ MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, PackedIntrinsics::OFFSET_P1);
+ MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, PackedIntrinsics::OFFSET_P2);
#undef MAYBE_SET_CONSTANT
if (!constant_intrinsics.empty()) {
- ceres::SubsetParameterization *subset_parameterization =
- new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS,
- constant_intrinsics);
+ ceres::SubsetParameterization* subset_parameterization =
+ new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS,
+ constant_intrinsics);
problem.SetParameterization(intrinsics_block, subset_parameterization);
}
@@ -800,8 +822,8 @@ void EuclideanBundleCommonIntrinsics(
LG << "Final intrinsics: " << *intrinsics;
if (evaluation) {
- EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_cameras_R_t,
- &problem, evaluation);
+ EuclideanBundlerPerformEvaluation(
+ tracks, reconstruction, &all_cameras_R_t, &problem, evaluation);
}
// Separate step to adjust positions of tracks which are
@@ -828,8 +850,8 @@ void EuclideanBundleCommonIntrinsics(
}
}
-void ProjectiveBundle(const Tracks & /*tracks*/,
- ProjectiveReconstruction * /*reconstruction*/) {
+void ProjectiveBundle(const Tracks& /*tracks*/,
+ ProjectiveReconstruction* /*reconstruction*/) {
// TODO(keir): Implement this! This can't work until we have a better bundler
// than SSBA, since SSBA has no support for projective bundling.
}
diff --git a/intern/libmv/libmv/simple_pipeline/bundle.h b/intern/libmv/libmv/simple_pipeline/bundle.h
index 5f420da0045..662313b396a 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.h
+++ b/intern/libmv/libmv/simple_pipeline/bundle.h
@@ -31,11 +31,8 @@ class ProjectiveReconstruction;
class Tracks;
struct BundleEvaluation {
- BundleEvaluation() :
- num_cameras(0),
- num_points(0),
- evaluate_jacobian(false) {
- }
+ BundleEvaluation()
+ : num_cameras(0), num_points(0), evaluate_jacobian(false) {}
// Number of cameras appeared in bundle adjustment problem
int num_cameras;
@@ -72,8 +69,8 @@ struct BundleEvaluation {
\sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames
*/
-void EuclideanBundle(const Tracks &tracks,
- EuclideanReconstruction *reconstruction);
+void EuclideanBundle(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction);
/*!
Refine camera poses and 3D coordinates using bundle adjustment.
@@ -109,9 +106,7 @@ enum BundleIntrinsics {
BUNDLE_RADIAL_K2 = (1 << 3),
BUNDLE_RADIAL_K3 = (1 << 4),
BUNDLE_RADIAL_K4 = (1 << 5),
- BUNDLE_RADIAL = (BUNDLE_RADIAL_K1 |
- BUNDLE_RADIAL_K2 |
- BUNDLE_RADIAL_K3 |
+ BUNDLE_RADIAL = (BUNDLE_RADIAL_K1 | BUNDLE_RADIAL_K2 | BUNDLE_RADIAL_K3 |
BUNDLE_RADIAL_K4),
BUNDLE_TANGENTIAL_P1 = (1 << 6),
@@ -122,13 +117,12 @@ enum BundleConstraints {
BUNDLE_NO_CONSTRAINTS = 0,
BUNDLE_NO_TRANSLATION = 1,
};
-void EuclideanBundleCommonIntrinsics(
- const Tracks &tracks,
- const int bundle_intrinsics,
- const int bundle_constraints,
- EuclideanReconstruction *reconstruction,
- CameraIntrinsics *intrinsics,
- BundleEvaluation *evaluation = NULL);
+void EuclideanBundleCommonIntrinsics(const Tracks& tracks,
+ const int bundle_intrinsics,
+ const int bundle_constraints,
+ EuclideanReconstruction* reconstruction,
+ CameraIntrinsics* intrinsics,
+ BundleEvaluation* evaluation = NULL);
/*!
Refine camera poses and 3D coordinates using bundle adjustment.
@@ -147,10 +141,9 @@ void EuclideanBundleCommonIntrinsics(
\sa ProjectiveResect, ProjectiveIntersect, ProjectiveReconstructTwoFrames
*/
-void ProjectiveBundle(const Tracks &tracks,
- ProjectiveReconstruction *reconstruction);
+void ProjectiveBundle(const Tracks& tracks,
+ ProjectiveReconstruction* reconstruction);
} // namespace libmv
-#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H
-
+#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H
diff --git a/intern/libmv/libmv/simple_pipeline/callbacks.h b/intern/libmv/libmv/simple_pipeline/callbacks.h
index 58f7b0d3cc9..a6855a9e5e7 100644
--- a/intern/libmv/libmv/simple_pipeline/callbacks.h
+++ b/intern/libmv/libmv/simple_pipeline/callbacks.h
@@ -26,7 +26,7 @@ namespace libmv {
class ProgressUpdateCallback {
public:
virtual ~ProgressUpdateCallback() {}
- virtual void invoke(double progress, const char *message) = 0;
+ virtual void invoke(double progress, const char* message) = 0;
};
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
index ccb6e3d34c8..b86e316b139 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
@@ -29,13 +29,10 @@ namespace libmv {
namespace internal {
LookupWarpGrid::LookupWarpGrid()
- : offset_(NULL),
- width_(0),
- height_(0),
- overscan_(0.0),
- threads_(1) {}
+ : offset_(NULL), width_(0), height_(0), overscan_(0.0), threads_(1) {
+}
-LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from)
+LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid& from)
: offset_(NULL),
width_(from.width_),
height_(from.height_),
@@ -48,11 +45,11 @@ LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from)
}
LookupWarpGrid::~LookupWarpGrid() {
- delete [] offset_;
+ delete[] offset_;
}
void LookupWarpGrid::Reset() {
- delete [] offset_;
+ delete[] offset_;
offset_ = NULL;
}
@@ -64,16 +61,16 @@ void LookupWarpGrid::SetThreads(int threads) {
} // namespace internal
CameraIntrinsics::CameraIntrinsics()
- : image_width_(0),
- image_height_(0),
- K_(Mat3::Identity()) {}
+ : image_width_(0), image_height_(0), K_(Mat3::Identity()) {
+}
-CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from)
+CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics& from)
: image_width_(from.image_width_),
image_height_(from.image_height_),
K_(from.K_),
distort_(from.distort_),
- undistort_(from.undistort_) {}
+ undistort_(from.undistort_) {
+}
// Set the image size in pixels.
void CameraIntrinsics::SetImageSize(int width, int height) {
@@ -89,16 +86,14 @@ void CameraIntrinsics::SetK(const Mat3 new_k) {
}
// Set both x and y focal length in pixels.
-void CameraIntrinsics::SetFocalLength(double focal_x,
- double focal_y) {
+void CameraIntrinsics::SetFocalLength(double focal_x, double focal_y) {
K_(0, 0) = focal_x;
K_(1, 1) = focal_y;
ResetLookupGrids();
}
// Set principal point in pixels.
-void CameraIntrinsics::SetPrincipalPoint(double cx,
- double cy) {
+void CameraIntrinsics::SetPrincipalPoint(double cx, double cy) {
K_(0, 2) = cx;
K_(1, 2) = cy;
ResetLookupGrids();
@@ -112,16 +107,16 @@ void CameraIntrinsics::SetThreads(int threads) {
void CameraIntrinsics::ImageSpaceToNormalized(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const {
+ double* normalized_x,
+ double* normalized_y) const {
*normalized_x = (image_x - principal_point_x()) / focal_length_x();
*normalized_y = (image_y - principal_point_y()) / focal_length_y();
}
void CameraIntrinsics::NormalizedToImageSpace(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const {
+ double* image_x,
+ double* image_y) const {
*image_x = normalized_x * focal_length_x() + principal_point_x();
*image_y = normalized_y * focal_length_y() + principal_point_y();
}
@@ -148,14 +143,13 @@ void CameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) {
// Polynomial model.
-PolynomialCameraIntrinsics::PolynomialCameraIntrinsics()
- : CameraIntrinsics() {
+PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() : CameraIntrinsics() {
SetRadialDistortion(0.0, 0.0, 0.0);
SetTangentialDistortion(0.0, 0.0);
}
PolynomialCameraIntrinsics::PolynomialCameraIntrinsics(
- const PolynomialCameraIntrinsics &from)
+ const PolynomialCameraIntrinsics& from)
: CameraIntrinsics(from) {
SetRadialDistortion(from.k1(), from.k2(), from.k3());
SetTangentialDistortion(from.p1(), from.p2());
@@ -170,8 +164,7 @@ void PolynomialCameraIntrinsics::SetRadialDistortion(double k1,
ResetLookupGrids();
}
-void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1,
- double p2) {
+void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, double p2) {
parameters_[OFFSET_P1] = p1;
parameters_[OFFSET_P2] = p2;
ResetLookupGrids();
@@ -179,31 +172,36 @@ void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1,
void PolynomialCameraIntrinsics::ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const {
+ double* image_x,
+ double* image_y) const {
ApplyPolynomialDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- k1(), k2(), k3(),
- p1(), p2(),
+ k1(),
+ k2(),
+ k3(),
+ p1(),
+ p2(),
normalized_x,
normalized_y,
image_x,
image_y);
}
-void PolynomialCameraIntrinsics::InvertIntrinsics(
- double image_x,
- double image_y,
- double *normalized_x,
- double *normalized_y) const {
+void PolynomialCameraIntrinsics::InvertIntrinsics(double image_x,
+ double image_y,
+ double* normalized_x,
+ double* normalized_y) const {
InvertPolynomialDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- k1(), k2(), k3(),
- p1(), p2(),
+ k1(),
+ k2(),
+ k3(),
+ p1(),
+ p2(),
image_x,
image_y,
normalized_x,
@@ -230,25 +228,22 @@ void PolynomialCameraIntrinsics::Unpack(
packed_intrinsics.GetK2(),
packed_intrinsics.GetK3());
- SetTangentialDistortion(packed_intrinsics.GetP1(),
- packed_intrinsics.GetP2());
+ SetTangentialDistortion(packed_intrinsics.GetP1(), packed_intrinsics.GetP2());
}
// Division model.
-DivisionCameraIntrinsics::DivisionCameraIntrinsics()
- : CameraIntrinsics() {
+DivisionCameraIntrinsics::DivisionCameraIntrinsics() : CameraIntrinsics() {
SetDistortion(0.0, 0.0);
}
DivisionCameraIntrinsics::DivisionCameraIntrinsics(
- const DivisionCameraIntrinsics &from)
+ const DivisionCameraIntrinsics& from)
: CameraIntrinsics(from) {
SetDistortion(from.k1(), from.k1());
}
-void DivisionCameraIntrinsics::SetDistortion(double k1,
- double k2) {
+void DivisionCameraIntrinsics::SetDistortion(double k1, double k2) {
parameters_[OFFSET_K1] = k1;
parameters_[OFFSET_K2] = k2;
ResetLookupGrids();
@@ -256,13 +251,14 @@ void DivisionCameraIntrinsics::SetDistortion(double k1,
void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const {
+ double* image_x,
+ double* image_y) const {
ApplyDivisionDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- k1(), k2(),
+ k1(),
+ k2(),
normalized_x,
normalized_y,
image_x,
@@ -271,21 +267,21 @@ void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x,
void DivisionCameraIntrinsics::InvertIntrinsics(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const {
+ double* normalized_x,
+ double* normalized_y) const {
InvertDivisionDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- k1(), k2(),
+ k1(),
+ k2(),
image_x,
image_y,
normalized_x,
normalized_y);
}
-void DivisionCameraIntrinsics::Pack(
- PackedIntrinsics* packed_intrinsics) const {
+void DivisionCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const {
CameraIntrinsics::Pack(packed_intrinsics);
packed_intrinsics->SetK1(k1());
@@ -301,13 +297,11 @@ void DivisionCameraIntrinsics::Unpack(
// Nuke model.
-NukeCameraIntrinsics::NukeCameraIntrinsics()
- : CameraIntrinsics() {
+NukeCameraIntrinsics::NukeCameraIntrinsics() : CameraIntrinsics() {
SetDistortion(0.0, 0.0);
}
-NukeCameraIntrinsics::NukeCameraIntrinsics(
- const NukeCameraIntrinsics &from)
+NukeCameraIntrinsics::NukeCameraIntrinsics(const NukeCameraIntrinsics& from)
: CameraIntrinsics(from) {
SetDistortion(from.k1(), from.k2());
}
@@ -320,14 +314,16 @@ void NukeCameraIntrinsics::SetDistortion(double k1, double k2) {
void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const {
+ double* image_x,
+ double* image_y) const {
ApplyNukeDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- image_width(), image_height(),
- k1(), k2(),
+ image_width(),
+ image_height(),
+ k1(),
+ k2(),
normalized_x,
normalized_y,
image_x,
@@ -335,31 +331,31 @@ void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x,
}
void NukeCameraIntrinsics::InvertIntrinsics(double image_x,
- double image_y,
- double *normalized_x,
- double *normalized_y) const {
+ double image_y,
+ double* normalized_x,
+ double* normalized_y) const {
InvertNukeDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- image_width(), image_height(),
- k1(), k2(),
+ image_width(),
+ image_height(),
+ k1(),
+ k2(),
image_x,
image_y,
normalized_x,
normalized_y);
}
-void NukeCameraIntrinsics::Pack(
- PackedIntrinsics* packed_intrinsics) const {
+void NukeCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const {
CameraIntrinsics::Pack(packed_intrinsics);
packed_intrinsics->SetK1(k1());
packed_intrinsics->SetK2(k2());
}
-void NukeCameraIntrinsics::Unpack(
- const PackedIntrinsics& packed_intrinsics) {
+void NukeCameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) {
CameraIntrinsics::Unpack(packed_intrinsics);
SetDistortion(packed_intrinsics.GetK1(), packed_intrinsics.GetK2());
@@ -367,14 +363,12 @@ void NukeCameraIntrinsics::Unpack(
// Brown model.
-BrownCameraIntrinsics::BrownCameraIntrinsics()
- : CameraIntrinsics() {
+BrownCameraIntrinsics::BrownCameraIntrinsics() : CameraIntrinsics() {
SetRadialDistortion(0.0, 0.0, 0.0, 0.0);
SetTangentialDistortion(0.0, 0.0);
}
-BrownCameraIntrinsics::BrownCameraIntrinsics(
- const BrownCameraIntrinsics &from)
+BrownCameraIntrinsics::BrownCameraIntrinsics(const BrownCameraIntrinsics& from)
: CameraIntrinsics(from) {
SetRadialDistortion(from.k1(), from.k2(), from.k3(), from.k4());
SetTangentialDistortion(from.p1(), from.p2());
@@ -391,8 +385,7 @@ void BrownCameraIntrinsics::SetRadialDistortion(double k1,
ResetLookupGrids();
}
-void BrownCameraIntrinsics::SetTangentialDistortion(double p1,
- double p2) {
+void BrownCameraIntrinsics::SetTangentialDistortion(double p1, double p2) {
parameters_[OFFSET_P1] = p1;
parameters_[OFFSET_P2] = p2;
ResetLookupGrids();
@@ -400,39 +393,45 @@ void BrownCameraIntrinsics::SetTangentialDistortion(double p1,
void BrownCameraIntrinsics::ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const {
+ double* image_x,
+ double* image_y) const {
ApplyBrownDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- k1(), k2(), k3(), k4(),
- p1(), p2(),
+ k1(),
+ k2(),
+ k3(),
+ k4(),
+ p1(),
+ p2(),
normalized_x,
normalized_y,
image_x,
image_y);
}
-void BrownCameraIntrinsics::InvertIntrinsics(
- double image_x,
- double image_y,
- double *normalized_x,
- double *normalized_y) const {
+void BrownCameraIntrinsics::InvertIntrinsics(double image_x,
+ double image_y,
+ double* normalized_x,
+ double* normalized_y) const {
InvertBrownDistortionModel(focal_length_x(),
focal_length_y(),
principal_point_x(),
principal_point_y(),
- k1(), k2(), k3(), k4(),
- p1(), p2(),
+ k1(),
+ k2(),
+ k3(),
+ k4(),
+ p1(),
+ p2(),
image_x,
image_y,
normalized_x,
normalized_y);
}
-void BrownCameraIntrinsics::Pack(
- PackedIntrinsics* packed_intrinsics) const {
+void BrownCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const {
CameraIntrinsics::Pack(packed_intrinsics);
packed_intrinsics->SetK1(k1());
@@ -444,8 +443,7 @@ void BrownCameraIntrinsics::Pack(
packed_intrinsics->SetP2(p2());
}
-void BrownCameraIntrinsics::Unpack(
- const PackedIntrinsics& packed_intrinsics) {
+void BrownCameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) {
CameraIntrinsics::Unpack(packed_intrinsics);
SetRadialDistortion(packed_intrinsics.GetK1(),
@@ -453,72 +451,65 @@ void BrownCameraIntrinsics::Unpack(
packed_intrinsics.GetK3(),
packed_intrinsics.GetK4());
- SetTangentialDistortion(packed_intrinsics.GetP1(),
- packed_intrinsics.GetP2());
+ SetTangentialDistortion(packed_intrinsics.GetP1(), packed_intrinsics.GetP2());
}
-std::ostream& operator <<(std::ostream &os,
- const CameraIntrinsics &intrinsics) {
+std::ostream& operator<<(std::ostream& os, const CameraIntrinsics& intrinsics) {
if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) {
os << "f=" << intrinsics.focal_length();
} else {
- os << "fx=" << intrinsics.focal_length_x()
+ os << "fx=" << intrinsics.focal_length_x()
<< " fy=" << intrinsics.focal_length_y();
}
os << " cx=" << intrinsics.principal_point_x()
<< " cy=" << intrinsics.principal_point_y()
- << " w=" << intrinsics.image_width()
- << " h=" << intrinsics.image_height();
+ << " w=" << intrinsics.image_width() << " h=" << intrinsics.image_height();
-#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \
- { \
- if (intrinsics->coeff() != 0.0) { \
- os << " " #coeff "=" << intrinsics->coeff(); \
- } \
- } (void) 0
+#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \
+ { \
+ if (intrinsics->coeff() != 0.0) { \
+ os << " " #coeff "=" << intrinsics->coeff(); \
+ } \
+ } \
+ (void)0
switch (intrinsics.GetDistortionModelType()) {
- case DISTORTION_MODEL_POLYNOMIAL:
- {
- const PolynomialCameraIntrinsics *polynomial_intrinsics =
- static_cast<const PolynomialCameraIntrinsics *>(&intrinsics);
- PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1);
- PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2);
- PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3);
- PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1);
- PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2);
- break;
- }
- case DISTORTION_MODEL_DIVISION:
- {
- const DivisionCameraIntrinsics *division_intrinsics =
- static_cast<const DivisionCameraIntrinsics *>(&intrinsics);
- PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1);
- PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2);
- break;
- }
- case DISTORTION_MODEL_NUKE:
- {
- const NukeCameraIntrinsics *nuke_intrinsics =
- static_cast<const NukeCameraIntrinsics *>(&intrinsics);
- PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1);
- PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2);
- break;
- }
- case DISTORTION_MODEL_BROWN:
- {
- const BrownCameraIntrinsics *brown_intrinsics =
- static_cast<const BrownCameraIntrinsics *>(&intrinsics);
- PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1);
- PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2);
- PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3);
- PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4);
- PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1);
- PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2);
- break;
- }
- default:
- LOG(FATAL) << "Unknown distortion model.";
+ case DISTORTION_MODEL_POLYNOMIAL: {
+ const PolynomialCameraIntrinsics* polynomial_intrinsics =
+ static_cast<const PolynomialCameraIntrinsics*>(&intrinsics);
+ PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1);
+ PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2);
+ PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3);
+ PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1);
+ PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2);
+ break;
+ }
+ case DISTORTION_MODEL_DIVISION: {
+ const DivisionCameraIntrinsics* division_intrinsics =
+ static_cast<const DivisionCameraIntrinsics*>(&intrinsics);
+ PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1);
+ PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2);
+ break;
+ }
+ case DISTORTION_MODEL_NUKE: {
+ const NukeCameraIntrinsics* nuke_intrinsics =
+ static_cast<const NukeCameraIntrinsics*>(&intrinsics);
+ PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1);
+ PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2);
+ break;
+ }
+ case DISTORTION_MODEL_BROWN: {
+ const BrownCameraIntrinsics* brown_intrinsics =
+ static_cast<const BrownCameraIntrinsics*>(&intrinsics);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2);
+ break;
+ }
+ default: LOG(FATAL) << "Unknown distortion model.";
}
#undef PRINT_NONZERO_COEFFICIENT
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
index ba67ec468dc..efe0735bd93 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
@@ -43,11 +43,11 @@ namespace internal {
class LookupWarpGrid {
public:
LookupWarpGrid();
- LookupWarpGrid(const LookupWarpGrid &from);
+ LookupWarpGrid(const LookupWarpGrid& from);
~LookupWarpGrid();
// Width and height og the image, measured in pixels.
- int width() const { return width_; }
+ int width() const { return width_; }
int height() const { return height_; }
// Overscan factor of the image, so that
@@ -61,8 +61,8 @@ class LookupWarpGrid {
//
// See comment for CameraIntrinsics::DistortBuffer to get more
// details about what overscan is.
- template<typename WarpFunction>
- void Update(const CameraIntrinsics &intrinsics,
+ template <typename WarpFunction>
+ void Update(const CameraIntrinsics& intrinsics,
int width,
int height,
double overscan);
@@ -71,12 +71,12 @@ class LookupWarpGrid {
//
// See comment for CameraIntrinsics::DistortBuffer to get more
// details about template type.
- template<typename PixelType>
- void Apply(const PixelType *input_buffer,
+ template <typename PixelType>
+ void Apply(const PixelType* input_buffer,
int width,
int height,
int channels,
- PixelType *output_buffer);
+ PixelType* output_buffer);
// Reset lookup grids.
// This will tag the grid for update without re-computing it.
@@ -105,15 +105,15 @@ class LookupWarpGrid {
//
// width and height corresponds to a size of buffer which will
// be warped later.
- template<typename WarpFunction>
- void Compute(const CameraIntrinsics &intrinsics,
+ template <typename WarpFunction>
+ void Compute(const CameraIntrinsics& intrinsics,
int width,
int height,
double overscan);
// This is a buffer which contains per-pixel offset of the
// pixels from input buffer to correspond the warping function.
- Offset *offset_;
+ Offset* offset_;
// Dimensions of the image this lookup grid processes.
int width_, height_;
@@ -130,19 +130,19 @@ class LookupWarpGrid {
class CameraIntrinsics {
public:
CameraIntrinsics();
- CameraIntrinsics(const CameraIntrinsics &from);
+ CameraIntrinsics(const CameraIntrinsics& from);
virtual ~CameraIntrinsics() {}
virtual DistortionModelType GetDistortionModelType() const = 0;
- int image_width() const { return image_width_; }
+ int image_width() const { return image_width_; }
int image_height() const { return image_height_; }
- const Mat3 &K() const { return K_; }
+ const Mat3& K() const { return K_; }
- double focal_length() const { return K_(0, 0); }
- double focal_length_x() const { return K_(0, 0); }
- double focal_length_y() const { return K_(1, 1); }
+ double focal_length() const { return K_(0, 0); }
+ double focal_length_x() const { return K_(0, 0); }
+ double focal_length_y() const { return K_(1, 1); }
double principal_point_x() const { return K_(0, 2); }
double principal_point_y() const { return K_(1, 2); }
@@ -166,14 +166,14 @@ class CameraIntrinsics {
// Convert image space coordinates to normalized.
void ImageSpaceToNormalized(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const;
+ double* normalized_x,
+ double* normalized_y) const;
// Convert normalized coordinates to image space.
void NormalizedToImageSpace(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const;
+ double* image_x,
+ double* image_y) const;
// Apply camera intrinsics to the normalized point to get image coordinates.
//
@@ -182,8 +182,8 @@ class CameraIntrinsics {
// coordinates in pixels.
virtual void ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const = 0;
+ double* image_x,
+ double* image_y) const = 0;
// Invert camera intrinsics on the image point to get normalized coordinates.
//
@@ -191,8 +191,8 @@ class CameraIntrinsics {
// coordinates to get normalized camera coordinates.
virtual void InvertIntrinsics(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const = 0;
+ double* normalized_x,
+ double* normalized_y) const = 0;
virtual void Pack(PackedIntrinsics* packed_intrinsics) const;
virtual void Unpack(const PackedIntrinsics& packed_intrinsics);
@@ -218,13 +218,13 @@ class CameraIntrinsics {
// But in fact PixelType might be any type for which multiplication by
// a scalar and addition are implemented. For example PixelType might be
// Vec3 as well.
- template<typename PixelType>
- void DistortBuffer(const PixelType *input_buffer,
+ template <typename PixelType>
+ void DistortBuffer(const PixelType* input_buffer,
int width,
int height,
double overscan,
int channels,
- PixelType *output_buffer);
+ PixelType* output_buffer);
// Undistort an image using the current camera instrinsics
//
@@ -247,13 +247,13 @@ class CameraIntrinsics {
// But in fact PixelType might be any type for which multiplication by
// a scalar and addition are implemented. For example PixelType might be
// Vec3 as well.
- template<typename PixelType>
- void UndistortBuffer(const PixelType *input_buffer,
+ template <typename PixelType>
+ void UndistortBuffer(const PixelType* input_buffer,
int width,
int height,
double overscan,
int channels,
- PixelType *output_buffer);
+ PixelType* output_buffer);
private:
// This is the size of the image. This is necessary to, for example, handle
@@ -290,7 +290,7 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics {
};
PolynomialCameraIntrinsics();
- PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics &from);
+ PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics& from);
DistortionModelType GetDistortionModelType() const override {
return DISTORTION_MODEL_POLYNOMIAL;
@@ -315,8 +315,8 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics {
// coordinates in pixels.
void ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const override;
+ double* image_x,
+ double* image_y) const override;
// Invert camera intrinsics on the image point to get normalized coordinates.
//
@@ -324,8 +324,8 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics {
// coordinates to get normalized camera coordinates.
void InvertIntrinsics(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const override;
+ double* normalized_x,
+ double* normalized_y) const override;
virtual void Pack(PackedIntrinsics* packed_intrinsics) const override;
virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override;
@@ -352,7 +352,7 @@ class DivisionCameraIntrinsics : public CameraIntrinsics {
};
DivisionCameraIntrinsics();
- DivisionCameraIntrinsics(const DivisionCameraIntrinsics &from);
+ DivisionCameraIntrinsics(const DivisionCameraIntrinsics& from);
DistortionModelType GetDistortionModelType() const override {
return DISTORTION_MODEL_DIVISION;
@@ -371,8 +371,8 @@ class DivisionCameraIntrinsics : public CameraIntrinsics {
// coordinates in pixels.
void ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const override;
+ double* image_x,
+ double* image_y) const override;
// Invert camera intrinsics on the image point to get normalized coordinates.
//
@@ -380,8 +380,8 @@ class DivisionCameraIntrinsics : public CameraIntrinsics {
// coordinates to get normalized camera coordinates.
void InvertIntrinsics(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const override;
+ double* normalized_x,
+ double* normalized_y) const override;
virtual void Pack(PackedIntrinsics* packed_intrinsics) const override;
virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override;
@@ -405,7 +405,7 @@ class NukeCameraIntrinsics : public CameraIntrinsics {
};
NukeCameraIntrinsics();
- NukeCameraIntrinsics(const NukeCameraIntrinsics &from);
+ NukeCameraIntrinsics(const NukeCameraIntrinsics& from);
DistortionModelType GetDistortionModelType() const override {
return DISTORTION_MODEL_NUKE;
@@ -424,8 +424,8 @@ class NukeCameraIntrinsics : public CameraIntrinsics {
// coordinates in pixels.
void ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const override;
+ double* image_x,
+ double* image_y) const override;
// Invert camera intrinsics on the image point to get normalized coordinates.
//
@@ -433,8 +433,8 @@ class NukeCameraIntrinsics : public CameraIntrinsics {
// coordinates to get normalized camera coordinates.
void InvertIntrinsics(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const override;
+ double* normalized_x,
+ double* normalized_y) const override;
virtual void Pack(PackedIntrinsics* packed_intrinsics) const override;
virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override;
@@ -462,7 +462,7 @@ class BrownCameraIntrinsics : public CameraIntrinsics {
};
BrownCameraIntrinsics();
- BrownCameraIntrinsics(const BrownCameraIntrinsics &from);
+ BrownCameraIntrinsics(const BrownCameraIntrinsics& from);
DistortionModelType GetDistortionModelType() const override {
return DISTORTION_MODEL_BROWN;
@@ -488,8 +488,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics {
// coordinates in pixels.
void ApplyIntrinsics(double normalized_x,
double normalized_y,
- double *image_x,
- double *image_y) const override;
+ double* image_x,
+ double* image_y) const override;
// Invert camera intrinsics on the image point to get normalized coordinates.
//
@@ -497,8 +497,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics {
// coordinates to get normalized camera coordinates.
void InvertIntrinsics(double image_x,
double image_y,
- double *normalized_x,
- double *normalized_y) const override;
+ double* normalized_x,
+ double* normalized_y) const override;
virtual void Pack(PackedIntrinsics* packed_intrinsics) const override;
virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override;
@@ -507,10 +507,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics {
double parameters_[NUM_PARAMETERS];
};
-
/// A human-readable representation of the camera intrinsic parameters.
-std::ostream& operator <<(std::ostream &os,
- const CameraIntrinsics &intrinsics);
+std::ostream& operator<<(std::ostream& os, const CameraIntrinsics& intrinsics);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h
index e1b53992dfd..c8c4700f5c6 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h
@@ -25,11 +25,11 @@ namespace {
// FIXME: C++ templates limitations makes thing complicated,
// but maybe there is a simpler method.
struct ApplyIntrinsicsFunction {
- ApplyIntrinsicsFunction(const CameraIntrinsics &intrinsics,
+ ApplyIntrinsicsFunction(const CameraIntrinsics& intrinsics,
double x,
double y,
- double *warp_x,
- double *warp_y) {
+ double* warp_x,
+ double* warp_y) {
double normalized_x, normalized_y;
intrinsics.ImageSpaceToNormalized(x, y, &normalized_x, &normalized_y);
intrinsics.ApplyIntrinsics(normalized_x, normalized_y, warp_x, warp_y);
@@ -37,14 +37,15 @@ struct ApplyIntrinsicsFunction {
};
struct InvertIntrinsicsFunction {
- InvertIntrinsicsFunction(const CameraIntrinsics &intrinsics,
+ InvertIntrinsicsFunction(const CameraIntrinsics& intrinsics,
double x,
double y,
- double *warp_x,
- double *warp_y) {
+ double* warp_x,
+ double* warp_y) {
double normalized_x, normalized_y;
intrinsics.InvertIntrinsics(x, y, &normalized_x, &normalized_y);
- intrinsics.NormalizedToImageSpace(normalized_x, normalized_y, warp_x, warp_y);
+ intrinsics.NormalizedToImageSpace(
+ normalized_x, normalized_y, warp_x, warp_y);
}
};
@@ -53,18 +54,18 @@ struct InvertIntrinsicsFunction {
namespace internal {
// TODO(MatthiasF): downsample lookup
-template<typename WarpFunction>
-void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics,
+template <typename WarpFunction>
+void LookupWarpGrid::Compute(const CameraIntrinsics& intrinsics,
int width,
int height,
double overscan) {
- double w = (double) width / (1.0 + overscan);
- double h = (double) height / (1.0 + overscan);
- double aspx = (double) w / intrinsics.image_width();
- double aspy = (double) h / intrinsics.image_height();
+ double w = (double)width / (1.0 + overscan);
+ double h = (double)height / (1.0 + overscan);
+ double aspx = (double)w / intrinsics.image_width();
+ double aspy = (double)h / intrinsics.image_height();
#if defined(_OPENMP)
-# pragma omp parallel for schedule(static) num_threads(threads_) \
- if (threads_ > 1 && height > 100)
+# pragma omp parallel for schedule(static) \
+ num_threads(threads_) if (threads_ > 1 && height > 100)
#endif
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
@@ -76,40 +77,47 @@ void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics,
warp_y = warp_y * aspy + 0.5 * overscan * h;
int ix = int(warp_x), iy = int(warp_y);
int fx = round((warp_x - ix) * 256), fy = round((warp_y - iy) * 256);
- if (fx == 256) { fx = 0; ix++; } // NOLINT
- if (fy == 256) { fy = 0; iy++; } // NOLINT
+ if (fx == 256) {
+ fx = 0;
+ ix++;
+ } // NOLINT
+ if (fy == 256) {
+ fy = 0;
+ iy++;
+ } // NOLINT
// Use nearest border pixel
- if (ix < 0) { ix = 0, fx = 0; } // NOLINT
- if (iy < 0) { iy = 0, fy = 0; } // NOLINT
- if (ix >= width - 2) ix = width - 2;
- if (iy >= height - 2) iy = height - 2;
-
- Offset offset = { (short) (ix - x),
- (short) (iy - y),
- (unsigned char) fx,
- (unsigned char) fy };
+ if (ix < 0) {
+ ix = 0, fx = 0;
+ } // NOLINT
+ if (iy < 0) {
+ iy = 0, fy = 0;
+ } // NOLINT
+ if (ix >= width - 2)
+ ix = width - 2;
+ if (iy >= height - 2)
+ iy = height - 2;
+
+ Offset offset = {(short)(ix - x),
+ (short)(iy - y),
+ (unsigned char)fx,
+ (unsigned char)fy};
offset_[y * width + x] = offset;
}
}
}
-template<typename WarpFunction>
-void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics,
+template <typename WarpFunction>
+void LookupWarpGrid::Update(const CameraIntrinsics& intrinsics,
int width,
int height,
double overscan) {
- if (width_ != width ||
- height_ != height ||
- overscan_ != overscan) {
+ if (width_ != width || height_ != height || overscan_ != overscan) {
Reset();
}
if (offset_ == NULL) {
offset_ = new Offset[width * height];
- Compute<WarpFunction>(intrinsics,
- width,
- height,
- overscan);
+ Compute<WarpFunction>(intrinsics, width, height, overscan);
}
width_ = width;
@@ -118,29 +126,30 @@ void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics,
}
// TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup
-template<typename PixelType>
-void LookupWarpGrid::Apply(const PixelType *input_buffer,
+template <typename PixelType>
+void LookupWarpGrid::Apply(const PixelType* input_buffer,
int width,
int height,
int channels,
- PixelType *output_buffer) {
+ PixelType* output_buffer) {
#if defined(_OPENMP)
-# pragma omp parallel for schedule(static) num_threads(threads_) \
- if (threads_ > 1 && height > 100)
+# pragma omp parallel for schedule(static) \
+ num_threads(threads_) if (threads_ > 1 && height > 100)
#endif
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Offset offset = offset_[y * width + x];
- const int pixel_index = ((y + offset.iy) * width +
- (x + offset.ix)) * channels;
- const PixelType *s = &input_buffer[pixel_index];
+ const int pixel_index =
+ ((y + offset.iy) * width + (x + offset.ix)) * channels;
+ const PixelType* s = &input_buffer[pixel_index];
for (int i = 0; i < channels; i++) {
output_buffer[(y * width + x) * channels + i] =
- ((s[i] * (256 - offset.fx) +
- s[channels + i] * offset.fx) * (256 - offset.fy) +
- (s[width * channels + i] * (256 - offset.fx) +
- s[width * channels + channels + i] * offset.fx) * offset.fy)
- / (256 * 256);
+ ((s[i] * (256 - offset.fx) + s[channels + i] * offset.fx) *
+ (256 - offset.fy) +
+ (s[width * channels + i] * (256 - offset.fx) +
+ s[width * channels + channels + i] * offset.fx) *
+ offset.fy) /
+ (256 * 256);
}
}
}
@@ -148,45 +157,33 @@ void LookupWarpGrid::Apply(const PixelType *input_buffer,
} // namespace internal
-template<typename PixelType>
-void CameraIntrinsics::DistortBuffer(const PixelType *input_buffer,
+template <typename PixelType>
+void CameraIntrinsics::DistortBuffer(const PixelType* input_buffer,
int width,
int height,
double overscan,
int channels,
- PixelType *output_buffer) {
+ PixelType* output_buffer) {
assert(channels >= 1);
assert(channels <= 4);
- distort_.Update<InvertIntrinsicsFunction>(*this,
- width,
- height,
- overscan);
- distort_.Apply<PixelType>(input_buffer,
- width,
- height,
- channels,
- output_buffer);
+ distort_.Update<InvertIntrinsicsFunction>(*this, width, height, overscan);
+ distort_.Apply<PixelType>(
+ input_buffer, width, height, channels, output_buffer);
}
-template<typename PixelType>
-void CameraIntrinsics::UndistortBuffer(const PixelType *input_buffer,
+template <typename PixelType>
+void CameraIntrinsics::UndistortBuffer(const PixelType* input_buffer,
int width,
int height,
double overscan,
int channels,
- PixelType *output_buffer) {
+ PixelType* output_buffer) {
assert(channels >= 1);
assert(channels <= 4);
- undistort_.Update<ApplyIntrinsicsFunction>(*this,
- width,
- height,
- overscan);
-
- undistort_.Apply<PixelType>(input_buffer,
- width,
- height,
- channels,
- output_buffer);
+ undistort_.Update<ApplyIntrinsicsFunction>(*this, width, height, overscan);
+
+ undistort_.Apply<PixelType>(
+ input_buffer, width, height, channels, output_buffer);
}
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
index 96d35a29ef8..cfcc2d16682 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
@@ -22,10 +22,10 @@
#include <iostream>
-#include "testing/testing.h"
#include "libmv/image/image.h"
#include "libmv/image/image_drawing.h"
#include "libmv/logging/logging.h"
+#include "testing/testing.h"
namespace libmv {
@@ -59,26 +59,36 @@ TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) {
const int N = 5;
double expected[N][N][2] = {
- { {75.312500, -24.687500}, {338.982239, -62.035522},
- {640.000000, -72.929688}, {941.017761, -62.035522},
- {1204.687500, -24.687500}},
-
- { {37.964478, 238.982239}, {323.664551, 223.664551},
- {640.000000, 219.193420}, {956.335449, 223.664551},
- {1242.035522, 238.982239}},
-
- { {27.070312, 540.000000}, {319.193420, 540.000000},
- {640.000000, 540.000000}, {960.806580, 540.000000},
- {1252.929688, 540.000000}},
-
- { {37.964478, 841.017761}, {323.664551, 856.335449},
- {640.000000, 860.806580}, {956.335449, 856.335449},
- {1242.035522, 841.017761}},
-
- { {75.312500, 1104.687500}, {338.982239, 1142.035522},
- {640.000000, 1152.929688}, {941.017761, 1142.035522},
- {1204.687500, 1104.687500}}
- };
+ {{75.312500, -24.687500},
+ {338.982239, -62.035522},
+ {640.000000, -72.929688},
+ {941.017761, -62.035522},
+ {1204.687500, -24.687500}},
+
+ {{37.964478, 238.982239},
+ {323.664551, 223.664551},
+ {640.000000, 219.193420},
+ {956.335449, 223.664551},
+ {1242.035522, 238.982239}},
+
+ {{27.070312, 540.000000},
+ {319.193420, 540.000000},
+ {640.000000, 540.000000},
+ {960.806580, 540.000000},
+ {1252.929688, 540.000000}},
+
+ {{37.964478, 841.017761},
+ {323.664551, 856.335449},
+ {640.000000, 860.806580},
+ {956.335449, 856.335449},
+ {1242.035522, 841.017761}},
+
+ {{75.312500, 1104.687500},
+ {338.982239, 1142.035522},
+ {640.000000, 1152.929688},
+ {941.017761, 1142.035522},
+ {1204.687500, 1104.687500}},
+ };
PolynomialCameraIntrinsics intrinsics;
intrinsics.SetFocalLength(1300.0, 1300.0);
@@ -89,12 +99,11 @@ TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
- double normalized_x = j * step - 0.5,
- normalized_y = i * step - 0.5;
+ double normalized_x = j * step - 0.5, normalized_y = i * step - 0.5;
double distorted_x, distorted_y;
- intrinsics.ApplyIntrinsics(normalized_x, normalized_y,
- &distorted_x, &distorted_y);
+ intrinsics.ApplyIntrinsics(
+ normalized_x, normalized_y, &distorted_x, &distorted_y);
EXPECT_NEAR(expected[i][j][0], distorted_x, 1e-6);
EXPECT_NEAR(expected[i][j][1], distorted_y, 1e-6);
@@ -106,43 +115,51 @@ TEST(PolynomialCameraIntrinsics, InvertIntrinsics) {
const int N = 5;
double expected[N][N][2] = {
- { {-0.524482, -0.437069}, {-0.226237, -0.403994},
- { 0.031876, -0.398446}, { 0.293917, -0.408218},
- { 0.632438, -0.465028}},
-
- { {-0.493496, -0.189173}, {-0.219052, -0.179936},
- { 0.030975, -0.178107}, { 0.283742, -0.181280},
- { 0.574557, -0.194335}},
-
- { {-0.488013, 0.032534}, {-0.217537, 0.031077},
- { 0.030781, 0.030781}, { 0.281635, 0.031293},
- { 0.566344, 0.033314}},
-
- { {-0.498696, 0.257660}, {-0.220424, 0.244041},
- { 0.031150, 0.241409}, { 0.285660, 0.245985},
- { 0.582670, 0.265629}},
-
- { {-0.550617, 0.532263}, {-0.230399, 0.477255},
- { 0.032380, 0.469510}, { 0.299986, 0.483311},
- { 0.684740, 0.584043}}
- };
+ {{-0.524482, -0.437069},
+ {-0.226237, -0.403994},
+ {0.031876, -0.398446},
+ {0.293917, -0.408218},
+ {0.632438, -0.465028}},
+
+ {{-0.493496, -0.189173},
+ {-0.219052, -0.179936},
+ {0.030975, -0.178107},
+ {0.283742, -0.181280},
+ {0.574557, -0.194335}},
+
+ {{-0.488013, 0.032534},
+ {-0.217537, 0.031077},
+ {0.030781, 0.030781},
+ {0.281635, 0.031293},
+ {0.566344, 0.033314}},
+
+ {{-0.498696, 0.257660},
+ {-0.220424, 0.244041},
+ {0.031150, 0.241409},
+ {0.285660, 0.245985},
+ {0.582670, 0.265629}},
+
+ {{-0.550617, 0.532263},
+ {-0.230399, 0.477255},
+ {0.032380, 0.469510},
+ {0.299986, 0.483311},
+ {0.684740, 0.584043}},
+ };
PolynomialCameraIntrinsics intrinsics;
intrinsics.SetFocalLength(1300.0, 1300.0);
intrinsics.SetPrincipalPoint(600.0, 500.0);
intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05);
- double step_x = 1280.0 / (N - 1),
- step_y = 1080.0 / (N - 1);
+ double step_x = 1280.0 / (N - 1), step_y = 1080.0 / (N - 1);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
- double distorted_x = j * step_x,
- distorted_y = i * step_y;
+ double distorted_x = j * step_x, distorted_y = i * step_y;
double normalized_x, normalized_y;
- intrinsics.InvertIntrinsics(distorted_x, distorted_y,
- &normalized_x, &normalized_y);
+ intrinsics.InvertIntrinsics(
+ distorted_x, distorted_y, &normalized_x, &normalized_y);
EXPECT_NEAR(expected[i][j][0], normalized_x, 1e-6);
EXPECT_NEAR(expected[i][j][1], normalized_y, 1e-6);
@@ -190,10 +207,11 @@ TEST(PolynomialCameraIntrinsics, IdentityDistortBuffer) {
FloatImage distorted_image(h, w);
intrinsics.SetImageSize(w, h);
intrinsics.SetFocalLength(10.0, 10.0);
- intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0);
+ intrinsics.SetPrincipalPoint((double)w / 2.0, (double)h / 2.0);
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
intrinsics.DistortBuffer(image.Data(),
- image.Width(), image.Height(),
+ image.Width(),
+ image.Height(),
0.0,
image.Depth(),
distorted_image.Data());
@@ -221,10 +239,11 @@ TEST(PolynomialCameraIntrinsics, IdentityUndistortBuffer) {
FloatImage distorted_image(h, w);
intrinsics.SetImageSize(w, h);
intrinsics.SetFocalLength(10.0, 10.0);
- intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0);
+ intrinsics.SetPrincipalPoint((double)w / 2.0, (double)h / 2.0);
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
intrinsics.UndistortBuffer(image.Data(),
- image.Width(), image.Height(),
+ image.Width(),
+ image.Height(),
0.0,
image.Depth(),
distorted_image.Data());
diff --git a/intern/libmv/libmv/simple_pipeline/detect.cc b/intern/libmv/libmv/simple_pipeline/detect.cc
index 46599a4c49e..0897c5598c6 100644
--- a/intern/libmv/libmv/simple_pipeline/detect.cc
+++ b/intern/libmv/libmv/simple_pipeline/detect.cc
@@ -22,14 +22,14 @@
**
****************************************************************************/
-#include <stdlib.h>
#include <memory.h>
+#include <stdlib.h>
#include <queue>
#include "libmv/base/scoped_ptr.h"
#include "libmv/image/array_nd.h"
-#include "libmv/image/image_converter.h"
#include "libmv/image/convolve.h"
+#include "libmv/image/image_converter.h"
#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/detect.h"
@@ -55,7 +55,7 @@ double kDefaultHarrisThreshold = 1e-5;
class FeatureComparison {
public:
- bool operator() (const Feature &left, const Feature &right) const {
+ bool operator()(const Feature& left, const Feature& right) const {
return right.score > left.score;
}
};
@@ -63,18 +63,17 @@ class FeatureComparison {
// Filter the features so there are no features closer than
// minimal distance to each other.
// This is a naive implementation with O(n^2) asymptotic.
-void FilterFeaturesByDistance(const vector<Feature> &all_features,
+void FilterFeaturesByDistance(const vector<Feature>& all_features,
int min_distance,
- vector<Feature> *detected_features) {
+ vector<Feature>* detected_features) {
const int min_distance_squared = min_distance * min_distance;
// Use priority queue to sort the features by their score.
//
// Do this on copy of the input features to prevent possible
// distortion in callee function behavior.
- std::priority_queue<Feature,
- std::vector<Feature>,
- FeatureComparison> priority_features;
+ std::priority_queue<Feature, std::vector<Feature>, FeatureComparison>
+ priority_features;
for (int i = 0; i < all_features.size(); i++) {
priority_features.push(all_features.at(i));
@@ -85,7 +84,7 @@ void FilterFeaturesByDistance(const vector<Feature> &all_features,
Feature a = priority_features.top();
for (int i = 0; i < detected_features->size(); i++) {
- Feature &b = detected_features->at(i);
+ Feature& b = detected_features->at(i);
if (Square(a.x - b.x) + Square(a.y - b.y) < min_distance_squared) {
ok = false;
break;
@@ -100,9 +99,9 @@ void FilterFeaturesByDistance(const vector<Feature> &all_features,
}
}
-void DetectFAST(const FloatImage &grayscale_image,
- const DetectOptions &options,
- vector<Feature> *detected_features) {
+void DetectFAST(const FloatImage& grayscale_image,
+ const DetectOptions& options,
+ vector<Feature>* detected_features) {
#ifndef LIBMV_NO_FAST_DETECTOR
const int min_distance = options.min_distance;
const int min_trackness = options.fast_min_trackness;
@@ -111,12 +110,14 @@ void DetectFAST(const FloatImage &grayscale_image,
const int height = grayscale_image.Width() - 2 * margin;
const int stride = grayscale_image.Width();
- scoped_array<unsigned char> byte_image(FloatImageToUCharArray(grayscale_image));
+ scoped_array<unsigned char> byte_image(
+ FloatImageToUCharArray(grayscale_image));
const int byte_image_offset = margin * stride + margin;
- // TODO(MatthiasF): Support targetting a feature count (binary search trackness)
+ // TODO(MatthiasF): Support targetting a feature count (binary search
+ // trackness)
int num_features;
- xy *all = fast9_detect(byte_image.get() + byte_image_offset,
+ xy* all = fast9_detect(byte_image.get() + byte_image_offset,
width,
height,
stride,
@@ -126,13 +127,13 @@ void DetectFAST(const FloatImage &grayscale_image,
free(all);
return;
}
- int *scores = fast9_score(byte_image.get() + byte_image_offset,
+ int* scores = fast9_score(byte_image.get() + byte_image_offset,
stride,
all,
num_features,
min_trackness);
// TODO(MatthiasF): merge with close feature suppression
- xy *nonmax = nonmax_suppression(all, scores, num_features, &num_features);
+ xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features);
free(all);
// Remove too close features
// TODO(MatthiasF): A resolution independent parameter would be better than
@@ -152,89 +153,104 @@ void DetectFAST(const FloatImage &grayscale_image,
free(scores);
free(nonmax);
#else
- (void) grayscale_image; // Ignored.
- (void) options; // Ignored.
- (void) detected_features; // Ignored.
+ (void)grayscale_image; // Ignored.
+ (void)options; // Ignored.
+ (void)detected_features; // Ignored.
LOG(FATAL) << "FAST detector is disabled in this build.";
#endif
}
#ifdef __SSE2__
-static unsigned int SAD(const ubyte* imageA, const ubyte* imageB,
- int strideA, int strideB) {
+static unsigned int SAD(const ubyte* imageA,
+ const ubyte* imageB,
+ int strideA,
+ int strideB) {
__m128i a = _mm_setzero_si128();
for (int i = 0; i < 16; i++) {
- a = _mm_adds_epu16(a,
- _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA+i*strideA)),
- _mm_loadu_si128((__m128i*)(imageB+i*strideB))));
+ a = _mm_adds_epu16(
+ a,
+ _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA + i * strideA)),
+ _mm_loadu_si128((__m128i*)(imageB + i * strideB))));
}
return _mm_extract_epi16(a, 0) + _mm_extract_epi16(a, 4);
}
#else
-static unsigned int SAD(const ubyte* imageA, const ubyte* imageB,
- int strideA, int strideB) {
+static unsigned int SAD(const ubyte* imageA,
+ const ubyte* imageB,
+ int strideA,
+ int strideB) {
unsigned int sad = 0;
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
- sad += abs((int)imageA[i*strideA+j] - imageB[i*strideB+j]);
+ sad += abs((int)imageA[i * strideA + j] - imageB[i * strideB + j]);
}
}
return sad;
}
#endif
-void DetectMORAVEC(const FloatImage &grayscale_image,
- const DetectOptions &options,
- vector<Feature> *detected_features) {
+void DetectMORAVEC(const FloatImage& grayscale_image,
+ const DetectOptions& options,
+ vector<Feature>* detected_features) {
const int distance = options.min_distance;
const int margin = options.margin;
- const unsigned char *pattern = options.moravec_pattern;
+ const unsigned char* pattern = options.moravec_pattern;
const int count = options.moravec_max_count;
const int width = grayscale_image.Width() - 2 * margin;
const int height = grayscale_image.Width() - 2 * margin;
const int stride = grayscale_image.Width();
- scoped_array<unsigned char> byte_image(FloatImageToUCharArray(grayscale_image));
+ scoped_array<unsigned char> byte_image(
+ FloatImageToUCharArray(grayscale_image));
unsigned short histogram[256];
memset(histogram, 0, sizeof(histogram));
- scoped_array<ubyte> scores(new ubyte[width*height]);
- memset(scores.get(), 0, width*height);
+ scoped_array<ubyte> scores(new ubyte[width * height]);
+ memset(scores.get(), 0, width * height);
const int r = 1; // radius for self similarity comparison
- for (int y = distance; y < height-distance; y++) {
- for (int x = distance; x < width-distance; x++) {
- const ubyte* s = &byte_image[y*stride+x];
- int score = // low self-similarity with overlapping patterns
- // OPTI: load pattern once
+ for (int y = distance; y < height - distance; y++) {
+ for (int x = distance; x < width - distance; x++) {
+ const ubyte* s = &byte_image[y * stride + x];
+ // low self-similarity with overlapping patterns
+ // OPTI: load pattern once
+ // clang-format off
+ int score =
SAD(s, s-r*stride-r, stride, stride)+SAD(s, s-r*stride, stride, stride)+SAD(s, s-r*stride+r, stride, stride)+
SAD(s, s -r, stride, stride)+ SAD(s, s +r, stride, stride)+
SAD(s, s+r*stride-r, stride, stride)+SAD(s, s+r*stride, stride, stride)+SAD(s, s+r*stride+r, stride, stride);
+ // clang-format on
+
score /= 256; // normalize
- if (pattern) // find only features similar to pattern
+ if (pattern) // find only features similar to pattern
score -= SAD(s, pattern, stride, 16);
- if (score <= 16) continue; // filter very self-similar features
+ if (score <= 16)
+ continue; // filter very self-similar features
score -= 16; // translate to score/histogram values
- if (score>255) score=255; // clip
- ubyte* c = &scores[y*width+x];
+ if (score > 255)
+ score = 255; // clip
+ ubyte* c = &scores[y * width + x];
for (int i = -distance; i < 0; i++) {
for (int j = -distance; j < distance; j++) {
- int s = c[i*width+j];
- if (s == 0) continue;
- if (s >= score) goto nonmax;
- c[i*width+j] = 0;
+ int s = c[i * width + j];
+ if (s == 0)
+ continue;
+ if (s >= score)
+ goto nonmax;
+ c[i * width + j] = 0;
histogram[s]--;
}
}
for (int i = 0, j = -distance; j < 0; j++) {
- int s = c[i*width+j];
- if (s == 0) continue;
- if (s >= score) goto nonmax;
- c[i*width+j] = 0;
+ int s = c[i * width + j];
+ if (s == 0)
+ continue;
+ if (s >= score)
+ goto nonmax;
+ c[i * width + j] = 0;
histogram[s]--;
}
c[0] = score, histogram[score]++;
- nonmax:
- { } // Do nothing.
+ nonmax : {} // Do nothing.
}
}
int min = 255, total = 0;
@@ -254,18 +270,16 @@ void DetectMORAVEC(const FloatImage &grayscale_image,
// Score calculation above uses top left corner of the
// patch as the origin, here we need to convert this value
// to a pattrn center by adding 8 pixels.
- detected_features->push_back(Feature((float) x + 8.0f,
- (float) y + 8.0f,
- (float) s,
- 16.0f));
+ detected_features->push_back(
+ Feature((float)x + 8.0f, (float)y + 8.0f, (float)s, 16.0f));
}
}
}
}
-void DetectHarris(const FloatImage &grayscale_image,
- const DetectOptions &options,
- vector<Feature> *detected_features) {
+void DetectHarris(const FloatImage& grayscale_image,
+ const DetectOptions& options,
+ vector<Feature>* detected_features) {
const double alpha = 0.06;
const double sigma = 0.9;
@@ -281,9 +295,7 @@ void DetectHarris(const FloatImage &grayscale_image,
MultiplyElements(gradient_y, gradient_y, &gradient_yy);
MultiplyElements(gradient_x, gradient_y, &gradient_xy);
- FloatImage gradient_xx_blurred,
- gradient_yy_blurred,
- gradient_xy_blurred;
+ FloatImage gradient_xx_blurred, gradient_yy_blurred, gradient_xy_blurred;
ConvolveGaussian(gradient_xx, sigma, &gradient_xx_blurred);
ConvolveGaussian(gradient_yy, sigma, &gradient_yy_blurred);
ConvolveGaussian(gradient_xy, sigma, &gradient_xy_blurred);
@@ -304,10 +316,8 @@ void DetectHarris(const FloatImage &grayscale_image,
double traceA = A.trace();
double harris_function = detA - alpha * traceA * traceA;
if (harris_function > threshold) {
- all_features.push_back(Feature((float) x,
- (float) y,
- (float) harris_function,
- 5.0f));
+ all_features.push_back(
+ Feature((float)x, (float)y, (float)harris_function, 5.0f));
}
}
}
@@ -318,17 +328,18 @@ void DetectHarris(const FloatImage &grayscale_image,
} // namespace
DetectOptions::DetectOptions()
- : type(DetectOptions::HARRIS),
- margin(0),
- min_distance(120),
- fast_min_trackness(kDefaultFastMinTrackness),
- moravec_max_count(0),
- moravec_pattern(NULL),
- harris_threshold(kDefaultHarrisThreshold) {}
-
-void Detect(const FloatImage &image,
- const DetectOptions &options,
- vector<Feature> *detected_features) {
+ : type(DetectOptions::HARRIS),
+ margin(0),
+ min_distance(120),
+ fast_min_trackness(kDefaultFastMinTrackness),
+ moravec_max_count(0),
+ moravec_pattern(NULL),
+ harris_threshold(kDefaultHarrisThreshold) {
+}
+
+void Detect(const FloatImage& image,
+ const DetectOptions& options,
+ vector<Feature>* detected_features) {
// Currently all the detectors requires image to be grayscale.
// Do it here to avoid code duplication.
FloatImage grayscale_image;
@@ -350,8 +361,7 @@ void Detect(const FloatImage &image,
}
}
-std::ostream& operator <<(std::ostream &os,
- const Feature &feature) {
+std::ostream& operator<<(std::ostream& os, const Feature& feature) {
os << "x: " << feature.x << ", y: " << feature.y;
os << ", score: " << feature.score;
os << ", size: " << feature.size;
diff --git a/intern/libmv/libmv/simple_pipeline/detect.h b/intern/libmv/libmv/simple_pipeline/detect.h
index 1035287bcf2..8ddf0025e4b 100644
--- a/intern/libmv/libmv/simple_pipeline/detect.h
+++ b/intern/libmv/libmv/simple_pipeline/detect.h
@@ -39,7 +39,7 @@ typedef unsigned char ubyte;
struct Feature {
Feature(float x, float y) : x(x), y(y) {}
Feature(float x, float y, float score, float size)
- : x(x), y(y), score(score), size(size) {}
+ : x(x), y(y), score(score), size(size) {}
// Position of the feature in pixels from top-left corner.
// Note: Libmv detector might eventually support subpixel precision.
@@ -88,9 +88,9 @@ struct DetectOptions {
// Find only features similar to this pattern. Only used by MORAVEC detector.
//
- // This is an image patch denoted in byte array with dimensions of 16px by 16px
- // used to filter features by similarity to this patch.
- unsigned char *moravec_pattern;
+ // This is an image patch denoted in byte array with dimensions of 16px by
+ // 16px used to filter features by similarity to this patch.
+ unsigned char* moravec_pattern;
// Threshold value of the Harris function to add new featrue
// to the result.
@@ -101,12 +101,11 @@ struct DetectOptions {
//
// Image could have 1-4 channels, it'll be converted to a grayscale
// by the detector function if needed.
-void Detect(const FloatImage &image,
- const DetectOptions &options,
- vector<Feature> *detected_features);
+void Detect(const FloatImage& image,
+ const DetectOptions& options,
+ vector<Feature>* detected_features);
-std::ostream& operator <<(std::ostream &os,
- const Feature &feature);
+std::ostream& operator<<(std::ostream& os, const Feature& feature);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/detect_test.cc b/intern/libmv/libmv/simple_pipeline/detect_test.cc
index b226ad96595..718598d04e1 100644
--- a/intern/libmv/libmv/simple_pipeline/detect_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/detect_test.cc
@@ -20,14 +20,14 @@
#include "libmv/simple_pipeline/detect.h"
-#include "testing/testing.h"
#include "libmv/logging/logging.h"
+#include "testing/testing.h"
namespace libmv {
namespace {
-void PreformSinglePointTest(const DetectOptions &options) {
+void PreformSinglePointTest(const DetectOptions& options) {
// Prepare the image.
FloatImage image(15, 15);
image.fill(1.0);
@@ -40,7 +40,7 @@ void PreformSinglePointTest(const DetectOptions &options) {
// Check detected features matches our expectations.
EXPECT_EQ(1, detected_features.size());
if (detected_features.size() == 1) {
- Feature &feature = detected_features[0];
+ Feature& feature = detected_features[0];
EXPECT_EQ(7, feature.x);
EXPECT_EQ(7, feature.y);
}
@@ -83,8 +83,8 @@ void PreformCheckerBoardTest(const DetectOptions &options) {
}
#endif
-void CheckExpectedFeatures(const vector<Feature> &detected_features,
- const vector<Feature> &expected_features) {
+void CheckExpectedFeatures(const vector<Feature>& detected_features,
+ const vector<Feature>& expected_features) {
EXPECT_EQ(expected_features.size(), detected_features.size());
// That's unsafe to iterate over vectors when their lengths
@@ -95,10 +95,10 @@ void CheckExpectedFeatures(const vector<Feature> &detected_features,
}
for (int i = 0; i < expected_features.size(); ++i) {
- const Feature &extected_feature = expected_features[i];
+ const Feature& extected_feature = expected_features[i];
bool found = false;
for (int j = 0; j < detected_features.size(); ++j) {
- const Feature &detected_feature = detected_features[j];
+ const Feature& detected_feature = detected_features[j];
if (extected_feature.x == detected_feature.x &&
extected_feature.y == detected_feature.y) {
found = true;
@@ -109,15 +109,14 @@ void CheckExpectedFeatures(const vector<Feature> &detected_features,
}
}
-void PreformSingleTriangleTest(const DetectOptions &options) {
+void PreformSingleTriangleTest(const DetectOptions& options) {
// Prepare the image.
FloatImage image(15, 21);
image.fill(1.0);
int vertex_x = 10, vertex_y = 5;
for (int i = 0; i < 6; ++i) {
- int current_x = vertex_x - i,
- current_y = vertex_y + i;
+ int current_x = vertex_x - i, current_y = vertex_y + i;
for (int j = 0; j < i * 2 + 1; ++j, ++current_x) {
image(current_y, current_x) = 0.0;
}
diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
index f602234b630..4556e3ceaf9 100644
--- a/intern/libmv/libmv/simple_pipeline/distortion_models.cc
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
@@ -41,25 +41,34 @@ struct InvertPolynomialIntrinsicsCostFunction {
const double p2,
const double image_x,
const double image_y)
- : focal_length_x_(focal_length_x),
- focal_length_y_(focal_length_y),
- principal_point_x_(principal_point_x),
- principal_point_y_(principal_point_y),
- k1_(k1), k2_(k2), k3_(k3),
- p1_(p1), p2_(p2),
- x_(image_x), y_(image_y) {}
-
- Vec2 operator()(const Vec2 &u) const {
+ : focal_length_x_(focal_length_x),
+ focal_length_y_(focal_length_y),
+ principal_point_x_(principal_point_x),
+ principal_point_y_(principal_point_y),
+ k1_(k1),
+ k2_(k2),
+ k3_(k3),
+ p1_(p1),
+ p2_(p2),
+ x_(image_x),
+ y_(image_y) {}
+
+ Vec2 operator()(const Vec2& u) const {
double xx, yy;
ApplyPolynomialDistortionModel(focal_length_x_,
focal_length_y_,
principal_point_x_,
principal_point_y_,
- k1_, k2_, k3_,
- p1_, p2_,
- u(0), u(1),
- &xx, &yy);
+ k1_,
+ k2_,
+ k3_,
+ p1_,
+ p2_,
+ u(0),
+ u(1),
+ &xx,
+ &yy);
Vec2 fx;
fx << (xx - x_), (yy - y_);
@@ -87,23 +96,28 @@ struct InvertDivisionIntrinsicsCostFunction {
const double k2,
const double image_x,
const double image_y)
- : focal_length_x_(focal_length_x),
- focal_length_y_(focal_length_y),
- principal_point_x_(principal_point_x),
- principal_point_y_(principal_point_y),
- k1_(k1), k2_(k2),
- x_(image_x), y_(image_y) {}
-
- Vec2 operator()(const Vec2 &u) const {
+ : focal_length_x_(focal_length_x),
+ focal_length_y_(focal_length_y),
+ principal_point_x_(principal_point_x),
+ principal_point_y_(principal_point_y),
+ k1_(k1),
+ k2_(k2),
+ x_(image_x),
+ y_(image_y) {}
+
+ Vec2 operator()(const Vec2& u) const {
double xx, yy;
ApplyDivisionDistortionModel(focal_length_x_,
focal_length_y_,
principal_point_x_,
principal_point_y_,
- k1_, k2_,
- u(0), u(1),
- &xx, &yy);
+ k1_,
+ k2_,
+ u(0),
+ u(1),
+ &xx,
+ &yy);
Vec2 fx;
fx << (xx - x_), (yy - y_);
@@ -134,25 +148,36 @@ struct InvertBrownIntrinsicsCostFunction {
const double p2,
const double image_x,
const double image_y)
- : focal_length_x_(focal_length_x),
- focal_length_y_(focal_length_y),
- principal_point_x_(principal_point_x),
- principal_point_y_(principal_point_y),
- k1_(k1), k2_(k2), k3_(k3), k4_(k4),
- p1_(p1), p2_(p2),
- x_(image_x), y_(image_y) {}
-
- Vec2 operator()(const Vec2 &u) const {
+ : focal_length_x_(focal_length_x),
+ focal_length_y_(focal_length_y),
+ principal_point_x_(principal_point_x),
+ principal_point_y_(principal_point_y),
+ k1_(k1),
+ k2_(k2),
+ k3_(k3),
+ k4_(k4),
+ p1_(p1),
+ p2_(p2),
+ x_(image_x),
+ y_(image_y) {}
+
+ Vec2 operator()(const Vec2& u) const {
double xx, yy;
ApplyBrownDistortionModel(focal_length_x_,
focal_length_y_,
principal_point_x_,
principal_point_y_,
- k1_, k2_, k3_, k4_,
- p1_, p2_,
- u(0), u(1),
- &xx, &yy);
+ k1_,
+ k2_,
+ k3_,
+ k4_,
+ p1_,
+ p2_,
+ u(0),
+ u(1),
+ &xx,
+ &yy);
Vec2 fx;
fx << (xx - x_), (yy - y_);
@@ -180,8 +205,8 @@ void InvertPolynomialDistortionModel(const double focal_length_x,
const double p2,
const double image_x,
const double image_y,
- double *normalized_x,
- double *normalized_y) {
+ double* normalized_x,
+ double* normalized_y) {
// Compute the initial guess. For a camera with no distortion, this will also
// be the final answer; the LM iteration will terminate immediately.
Vec2 normalized;
@@ -194,13 +219,17 @@ void InvertPolynomialDistortionModel(const double focal_length_x,
focal_length_y,
principal_point_x,
principal_point_y,
- k1, k2, k3,
- p1, p2,
- image_x, image_y);
+ k1,
+ k2,
+ k3,
+ p1,
+ p2,
+ image_x,
+ image_y);
Solver::SolverParameters params;
Solver solver(intrinsics_cost);
- /*Solver::Results results =*/ solver.minimize(params, &normalized);
+ /*Solver::Results results =*/solver.minimize(params, &normalized);
// TODO(keir): Better error handling.
@@ -216,8 +245,8 @@ void InvertDivisionDistortionModel(const double focal_length_x,
const double k2,
const double image_x,
const double image_y,
- double *normalized_x,
- double *normalized_y) {
+ double* normalized_x,
+ double* normalized_y) {
// Compute the initial guess. For a camera with no distortion, this will also
// be the final answer; the LM iteration will terminate immediately.
Vec2 normalized;
@@ -231,12 +260,14 @@ void InvertDivisionDistortionModel(const double focal_length_x,
focal_length_y,
principal_point_x,
principal_point_y,
- k1, k2,
- image_x, image_y);
+ k1,
+ k2,
+ image_x,
+ image_y);
Solver::SolverParameters params;
Solver solver(intrinsics_cost);
- /*Solver::Results results =*/ solver.minimize(params, &normalized);
+ /*Solver::Results results =*/solver.minimize(params, &normalized);
// TODO(keir): Better error handling.
@@ -256,8 +287,8 @@ void InvertBrownDistortionModel(const double focal_length_x,
const double p2,
const double image_x,
const double image_y,
- double *normalized_x,
- double *normalized_y) {
+ double* normalized_x,
+ double* normalized_y) {
// Compute the initial guess. For a camera with no distortion, this will also
// be the final answer; the LM iteration will terminate immediately.
Vec2 normalized;
@@ -270,13 +301,18 @@ void InvertBrownDistortionModel(const double focal_length_x,
focal_length_y,
principal_point_x,
principal_point_y,
- k1, k2, k3, k4,
- p1, p2,
- image_x, image_y);
+ k1,
+ k2,
+ k3,
+ k4,
+ p1,
+ p2,
+ image_x,
+ image_y);
Solver::SolverParameters params;
Solver solver(intrinsics_cost);
- /*Solver::Results results =*/ solver.minimize(params, &normalized);
+ /*Solver::Results results =*/solver.minimize(params, &normalized);
// TODO(keir): Better error handling.
@@ -299,31 +335,36 @@ struct ApplyNukeIntrinsicsCostFunction {
const double k2,
const double expected_normalized_x,
const double expected_normalized_y)
- : focal_length_x_(focal_length_x),
- focal_length_y_(focal_length_y),
- principal_point_x_(principal_point_x),
- principal_point_y_(principal_point_y),
- image_width_(image_width),
- image_height_(image_height),
- k1_(k1), k2_(k2),
- expected_normalized_x_(expected_normalized_x),
- expected_normalized_y_(expected_normalized_y) {}
-
- Vec2 operator()(const Vec2 &image_coordinate) const {
+ : focal_length_x_(focal_length_x),
+ focal_length_y_(focal_length_y),
+ principal_point_x_(principal_point_x),
+ principal_point_y_(principal_point_y),
+ image_width_(image_width),
+ image_height_(image_height),
+ k1_(k1),
+ k2_(k2),
+ expected_normalized_x_(expected_normalized_x),
+ expected_normalized_y_(expected_normalized_y) {}
+
+ Vec2 operator()(const Vec2& image_coordinate) const {
double actual_normalized_x, actual_normalized_y;
InvertNukeDistortionModel(focal_length_x_,
focal_length_y_,
principal_point_x_,
principal_point_y_,
- image_width_, image_height_,
- k1_, k2_,
- image_coordinate(0), image_coordinate(1),
- &actual_normalized_x, &actual_normalized_y);
+ image_width_,
+ image_height_,
+ k1_,
+ k2_,
+ image_coordinate(0),
+ image_coordinate(1),
+ &actual_normalized_x,
+ &actual_normalized_y);
Vec2 fx;
fx << (actual_normalized_x - expected_normalized_x_),
- (actual_normalized_y - expected_normalized_y_);
+ (actual_normalized_y - expected_normalized_y_);
return fx;
}
double focal_length_x_;
@@ -346,8 +387,8 @@ void ApplyNukeDistortionModel(const double focal_length_x,
const double k2,
const double normalized_x,
const double normalized_y,
- double *image_x,
- double *image_y) {
+ double* image_x,
+ double* image_y) {
// Compute the initial guess. For a camera with no distortion, this will also
// be the final answer; the LM iteration will terminate immediately.
Vec2 image;
@@ -363,12 +404,14 @@ void ApplyNukeDistortionModel(const double focal_length_x,
principal_point_y,
image_width,
image_height,
- k1, k2,
- normalized_x, normalized_y);
+ k1,
+ k2,
+ normalized_x,
+ normalized_y);
Solver::SolverParameters params;
Solver solver(intrinsics_cost);
- /*Solver::Results results =*/ solver.minimize(params, &image);
+ /*Solver::Results results =*/solver.minimize(params, &image);
// TODO(keir): Better error handling.
diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h
index 51300477956..5fe9fee8d54 100644
--- a/intern/libmv/libmv/simple_pipeline/distortion_models.h
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h
@@ -46,37 +46,37 @@ void InvertPolynomialDistortionModel(const double focal_length_x,
const double p2,
const double image_x,
const double image_y,
- double *normalized_x,
- double *normalized_y);
+ double* normalized_x,
+ double* normalized_y);
// Apply camera intrinsics to the normalized point to get image coordinates.
// This applies the radial lens distortion to a point which is in normalized
// camera coordinates (i.e. the principal point is at (0, 0)) to get image
// coordinates in pixels. Templated for use with autodifferentiation.
template <typename T>
-inline void ApplyPolynomialDistortionModel(const T &focal_length_x,
- const T &focal_length_y,
- const T &principal_point_x,
- const T &principal_point_y,
- const T &k1,
- const T &k2,
- const T &k3,
- const T &p1,
- const T &p2,
- const T &normalized_x,
- const T &normalized_y,
- T *image_x,
- T *image_y) {
+inline void ApplyPolynomialDistortionModel(const T& focal_length_x,
+ const T& focal_length_y,
+ const T& principal_point_x,
+ const T& principal_point_y,
+ const T& k1,
+ const T& k2,
+ const T& k3,
+ const T& p1,
+ const T& p2,
+ const T& normalized_x,
+ const T& normalized_y,
+ T* image_x,
+ T* image_y) {
T x = normalized_x;
T y = normalized_y;
// Apply distortion to the normalized points to get (xd, yd).
- T r2 = x*x + y*y;
+ T r2 = x * x + y * y;
T r4 = r2 * r2;
T r6 = r4 * r2;
- T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6);
- T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x);
- T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y);
+ T r_coeff = (T(1) + k1 * r2 + k2 * r4 + k3 * r6);
+ T xd = x * r_coeff + T(2) * p1 * x * y + p2 * (r2 + T(2) * x * x);
+ T yd = y * r_coeff + T(2) * p2 * x * y + p1 * (r2 + T(2) * y * y);
// Apply focal length and principal point to get the final image coordinates.
*image_x = focal_length_x * xd + principal_point_x;
@@ -96,8 +96,8 @@ void InvertDivisionDistortionModel(const double focal_length_x,
const double k2,
const double image_x,
const double image_y,
- double *normalized_x,
- double *normalized_y);
+ double* normalized_x,
+ double* normalized_y);
// Apply camera intrinsics to the normalized point to get image coordinates.
// This applies the radial lens distortion to a point which is in normalized
@@ -106,20 +106,19 @@ void InvertDivisionDistortionModel(const double focal_length_x,
//
// Uses division distortion model.
template <typename T>
-inline void ApplyDivisionDistortionModel(const T &focal_length_x,
- const T &focal_length_y,
- const T &principal_point_x,
- const T &principal_point_y,
- const T &k1,
- const T &k2,
- const T &normalized_x,
- const T &normalized_y,
- T *image_x,
- T *image_y) {
-
+inline void ApplyDivisionDistortionModel(const T& focal_length_x,
+ const T& focal_length_y,
+ const T& principal_point_x,
+ const T& principal_point_y,
+ const T& k1,
+ const T& k2,
+ const T& normalized_x,
+ const T& normalized_y,
+ T* image_x,
+ T* image_y) {
T x = normalized_x;
T y = normalized_y;
- T r2 = x*x + y*y;
+ T r2 = x * x + y * y;
T r4 = r2 * r2;
T xd = x / (T(1) + k1 * r2 + k2 * r4);
@@ -136,18 +135,18 @@ inline void ApplyDivisionDistortionModel(const T &focal_length_x,
//
// Uses Nuke distortion model.
template <typename T>
-void InvertNukeDistortionModel(const T &focal_length_x,
- const T &focal_length_y,
- const T &principal_point_x,
- const T &principal_point_y,
+void InvertNukeDistortionModel(const T& focal_length_x,
+ const T& focal_length_y,
+ const T& principal_point_x,
+ const T& principal_point_y,
const int image_width,
const int image_height,
- const T &k1,
- const T &k2,
- const T &image_x,
- const T &image_y,
- T *normalized_x,
- T *normalized_y) {
+ const T& k1,
+ const T& k2,
+ const T& image_x,
+ const T& image_y,
+ T* normalized_x,
+ T* normalized_y) {
// According to the documentation:
//
// xu = xd / (1 + k0 * rd^2 + k1 * rd^4)
@@ -174,9 +173,9 @@ void InvertNukeDistortionModel(const T &focal_length_x,
const T xd = (image_x - principal_point_x) / max_half_image_size;
const T yd = (image_y - principal_point_y) / max_half_image_size;
- T rd2 = xd*xd + yd*yd;
+ T rd2 = xd * xd + yd * yd;
T rd4 = rd2 * rd2;
- T r_coeff = T(1) / (T(1) + k1*rd2 + k2*rd4);
+ T r_coeff = T(1) / (T(1) + k1 * rd2 + k2 * rd4);
T xu = xd * r_coeff;
T yu = yd * r_coeff;
@@ -200,8 +199,8 @@ void ApplyNukeDistortionModel(const double focal_length_x,
const double k2,
const double normalized_x,
const double normalized_y,
- double *image_x,
- double *image_y);
+ double* image_x,
+ double* image_y);
// Invert camera intrinsics on the image point to get normalized coordinates.
// This inverts the radial lens distortion to a point which is in image pixel
@@ -218,24 +217,24 @@ void InvertBrownDistortionModel(const double focal_length_x,
const double p2,
const double image_x,
const double image_y,
- double *normalized_x,
- double *normalized_y);
+ double* normalized_x,
+ double* normalized_y);
template <typename T>
-inline void ApplyBrownDistortionModel(const T &focal_length_x,
- const T &focal_length_y,
- const T &principal_point_x,
- const T &principal_point_y,
- const T &k1,
- const T &k2,
- const T &k3,
- const T &k4,
- const T &p1,
- const T &p2,
- const T &normalized_x,
- const T &normalized_y,
- T *image_x,
- T *image_y) {
+inline void ApplyBrownDistortionModel(const T& focal_length_x,
+ const T& focal_length_y,
+ const T& principal_point_x,
+ const T& principal_point_y,
+ const T& k1,
+ const T& k2,
+ const T& k3,
+ const T& k4,
+ const T& p1,
+ const T& p2,
+ const T& normalized_x,
+ const T& normalized_y,
+ T* image_x,
+ T* image_y) {
T x = normalized_x;
T y = normalized_y;
@@ -253,8 +252,8 @@ inline void ApplyBrownDistortionModel(const T &focal_length_x,
// Apply focal length and principal point to get the final image coordinates.
*image_x = focal_length_x * xd + principal_point_x;
*image_y = focal_length_y * yd + principal_point_y;
-} // namespace libmv
+} // namespace libmv
-}
+} // namespace libmv
#endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_
diff --git a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
index 7a086c375d5..10ad0929007 100644
--- a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
+++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
@@ -32,8 +32,9 @@
namespace libmv {
namespace {
-void GetImagesInMarkers(const vector<Marker> &markers,
- int *image1, int *image2) {
+void GetImagesInMarkers(const vector<Marker>& markers,
+ int* image1,
+ int* image2) {
if (markers.size() < 2) {
return;
}
@@ -50,10 +51,11 @@ void GetImagesInMarkers(const vector<Marker> &markers,
} // namespace
-bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction) {
+bool EuclideanReconstructTwoFrames(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction) {
if (markers.size() < 16) {
- LG << "Not enough markers to initialize from two frames: " << markers.size();
+ LG << "Not enough markers to initialize from two frames: "
+ << markers.size();
return false;
}
@@ -76,10 +78,8 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
Mat3 R;
Vec3 t;
Mat3 K = Mat3::Identity();
- if (!MotionFromEssentialAndCorrespondence(E,
- K, x1.col(0),
- K, x2.col(0),
- &R, &t)) {
+ if (!MotionFromEssentialAndCorrespondence(
+ E, K, x1.col(0), K, x2.col(0), &R, &t)) {
LG << "Failed to compute R and t from E and K.";
return false;
}
@@ -88,14 +88,14 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero());
reconstruction->InsertCamera(image2, R, t);
- LG << "From two frame reconstruction got:\nR:\n" << R
- << "\nt:" << t.transpose();
+ LG << "From two frame reconstruction got:\nR:\n"
+ << R << "\nt:" << t.transpose();
return true;
}
namespace {
-Mat3 DecodeF(const Vec9 &encoded_F) {
+Mat3 DecodeF(const Vec9& encoded_F) {
// Decode F and force it to be rank 2.
Map<const Mat3> full_rank_F(encoded_F.data(), 3, 3);
Eigen::JacobiSVD<Mat3> svd(full_rank_F,
@@ -110,22 +110,22 @@ Mat3 DecodeF(const Vec9 &encoded_F) {
// doing a full SVD of F at each iteration. This uses sampson error.
struct FundamentalSampsonCostFunction {
public:
- typedef Vec FMatrixType;
+ typedef Vec FMatrixType;
typedef Vec9 XMatrixType;
// Assumes markers are ordered by track.
- explicit FundamentalSampsonCostFunction(const vector<Marker> &markers)
- : markers(markers) {}
+ explicit FundamentalSampsonCostFunction(const vector<Marker>& markers)
+ : markers(markers) {}
- Vec operator()(const Vec9 &encoded_F) const {
+ Vec operator()(const Vec9& encoded_F) const {
// Decode F and force it to be rank 2.
Mat3 F = DecodeF(encoded_F);
Vec residuals(markers.size() / 2);
residuals.setZero();
for (int i = 0; i < markers.size() / 2; ++i) {
- const Marker &marker1 = markers[2*i + 0];
- const Marker &marker2 = markers[2*i + 1];
+ const Marker& marker1 = markers[2 * i + 0];
+ const Marker& marker2 = markers[2 * i + 1];
CHECK_EQ(marker1.track, marker2.track);
Vec2 x1(marker1.x, marker1.y);
Vec2 x2(marker2.x, marker2.y);
@@ -134,13 +134,13 @@ struct FundamentalSampsonCostFunction {
}
return residuals;
}
- const vector<Marker> &markers;
+ const vector<Marker>& markers;
};
} // namespace
-bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction) {
+bool ProjectiveReconstructTwoFrames(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction) {
if (markers.size() < 16) {
return false;
}
diff --git a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
index 32cd4285190..354db14971f 100644
--- a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
+++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
@@ -37,18 +37,19 @@ class ProjectiveReconstruction;
tracks visible in both frames. The pose estimation of the camera for
these frames will be inserted into \a *reconstruction.
- \note The two frames need to have both enough parallax and enough common tracks
- for accurate reconstruction. At least 8 tracks are suggested.
- \note The origin of the coordinate system is defined to be the camera of
- the first keyframe.
- \note This assumes a calibrated reconstruction, e.g. the markers are
- already corrected for camera intrinsics and radial distortion.
+ \note The two frames need to have both enough parallax and enough common
+ tracks for accurate reconstruction. At least 8 tracks are suggested.
+ \note The origin of the coordinate system is defined to be the camera of the
+ first keyframe.
+ \note This assumes a calibrated reconstruction, e.g. the
+ markers are already corrected for camera intrinsics and radial
+ distortion.
\note This assumes an outlier-free set of markers.
\sa EuclideanResect, EuclideanIntersect, EuclideanBundle
*/
-bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction);
+bool EuclideanReconstructTwoFrames(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction);
/*!
Initialize the \link ProjectiveReconstruction reconstruction \endlink using
@@ -58,17 +59,17 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
tracks visible in both frames. An estimate of the projection matrices for
the two frames will get added to the reconstruction.
- \note The two frames need to have both enough parallax and enough common tracks
- for accurate reconstruction. At least 8 tracks are suggested.
- \note The origin of the coordinate system is defined to be the camera of
- the first keyframe.
+ \note The two frames need to have both enough parallax and enough common
+ tracks for accurate reconstruction. At least 8 tracks are suggested.
+ \note The origin of the coordinate system is defined to be the camera of the
+ first keyframe.
\note This assumes the markers are already corrected for radial distortion.
\note This assumes an outlier-free set of markers.
\sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle
*/
-bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction);
+bool ProjectiveReconstructTwoFrames(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction);
} // namespace libmv
#endif // LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
diff --git a/intern/libmv/libmv/simple_pipeline/intersect.cc b/intern/libmv/libmv/simple_pipeline/intersect.cc
index ddb713684a4..86efd26f778 100644
--- a/intern/libmv/libmv/simple_pipeline/intersect.cc
+++ b/intern/libmv/libmv/simple_pipeline/intersect.cc
@@ -22,11 +22,11 @@
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
+#include "libmv/multiview/nviewtriangulation.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/triangulation.h"
-#include "libmv/multiview/nviewtriangulation.h"
-#include "libmv/numeric/numeric.h"
#include "libmv/numeric/levenberg_marquardt.h"
+#include "libmv/numeric/numeric.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
@@ -38,12 +38,12 @@ namespace {
class EuclideanIntersectCostFunctor {
public:
- EuclideanIntersectCostFunctor(const Marker &marker,
- const EuclideanCamera &camera)
+ EuclideanIntersectCostFunctor(const Marker& marker,
+ const EuclideanCamera& camera)
: marker_(marker), camera_(camera) {}
- template<typename T>
- bool operator()(const T *X, T *residuals) const {
+ template <typename T>
+ bool operator()(const T* X, T* residuals) const {
typedef Eigen::Matrix<T, 3, 3> Mat3;
typedef Eigen::Matrix<T, 3, 1> Vec3;
@@ -60,14 +60,14 @@ class EuclideanIntersectCostFunctor {
return true;
}
- const Marker &marker_;
- const EuclideanCamera &camera_;
+ const Marker& marker_;
+ const EuclideanCamera& camera_;
};
} // namespace
-bool EuclideanIntersect(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction) {
+bool EuclideanIntersect(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction) {
if (markers.size() < 2) {
return false;
}
@@ -78,7 +78,7 @@ bool EuclideanIntersect(const vector<Marker> &markers,
vector<Mat34> cameras;
Mat34 P;
for (int i = 0; i < markers.size(); ++i) {
- EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+ EuclideanCamera* camera = reconstruction->CameraForImage(markers[i].image);
P_From_KRt(K, camera->R, camera->t, &P);
cameras.push_back(P);
}
@@ -103,19 +103,19 @@ bool EuclideanIntersect(const vector<Marker> &markers,
// Add residual blocks to the problem.
int num_residuals = 0;
for (int i = 0; i < markers.size(); ++i) {
- const Marker &marker = markers[i];
+ const Marker& marker = markers[i];
if (marker.weight != 0.0) {
- const EuclideanCamera &camera =
+ const EuclideanCamera& camera =
*reconstruction->CameraForImage(marker.image);
problem.AddResidualBlock(
- new ceres::AutoDiffCostFunction<
- EuclideanIntersectCostFunctor,
- 2, /* num_residuals */
- 3>(new EuclideanIntersectCostFunctor(marker, camera)),
+ new ceres::AutoDiffCostFunction<EuclideanIntersectCostFunctor,
+ 2, /* num_residuals */
+ 3>(
+ new EuclideanIntersectCostFunctor(marker, camera)),
NULL,
&X(0));
- num_residuals++;
+ num_residuals++;
}
}
@@ -126,9 +126,9 @@ bool EuclideanIntersect(const vector<Marker> &markers,
if (!num_residuals) {
LG << "Skipping running minimizer with zero residuals";
- // We still add 3D point for the track regardless it was
- // optimized or not. If track is a constant zero it'll use
- // algebraic intersection result as a 3D coordinate.
+ // We still add 3D point for the track regardless it was
+ // optimized or not. If track is a constant zero it'll use
+ // algebraic intersection result as a 3D coordinate.
Vec3 point = X.head<3>();
reconstruction->InsertPoint(markers[0].track, point);
@@ -152,12 +152,12 @@ bool EuclideanIntersect(const vector<Marker> &markers,
// Try projecting the point; make sure it's in front of everyone.
for (int i = 0; i < cameras.size(); ++i) {
- const EuclideanCamera &camera =
+ const EuclideanCamera& camera =
*reconstruction->CameraForImage(markers[i].image);
Vec3 x = camera.R * X + camera.t;
if (x(2) < 0) {
- LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
- << ": " << x.transpose();
+ LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image << ": "
+ << x.transpose();
return false;
}
}
@@ -173,35 +173,35 @@ namespace {
struct ProjectiveIntersectCostFunction {
public:
- typedef Vec FMatrixType;
+ typedef Vec FMatrixType;
typedef Vec4 XMatrixType;
ProjectiveIntersectCostFunction(
- const vector<Marker> &markers,
- const ProjectiveReconstruction &reconstruction)
- : markers(markers), reconstruction(reconstruction) {}
+ const vector<Marker>& markers,
+ const ProjectiveReconstruction& reconstruction)
+ : markers(markers), reconstruction(reconstruction) {}
- Vec operator()(const Vec4 &X) const {
+ Vec operator()(const Vec4& X) const {
Vec residuals(2 * markers.size());
residuals.setZero();
for (int i = 0; i < markers.size(); ++i) {
- const ProjectiveCamera &camera =
+ const ProjectiveCamera& camera =
*reconstruction.CameraForImage(markers[i].image);
Vec3 projected = camera.P * X;
projected /= projected(2);
- residuals[2*i + 0] = projected(0) - markers[i].x;
- residuals[2*i + 1] = projected(1) - markers[i].y;
+ residuals[2 * i + 0] = projected(0) - markers[i].x;
+ residuals[2 * i + 1] = projected(1) - markers[i].y;
}
return residuals;
}
- const vector<Marker> &markers;
- const ProjectiveReconstruction &reconstruction;
+ const vector<Marker>& markers;
+ const ProjectiveReconstruction& reconstruction;
};
} // namespace
-bool ProjectiveIntersect(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction) {
+bool ProjectiveIntersect(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction) {
if (markers.size() < 2) {
return false;
}
@@ -209,7 +209,7 @@ bool ProjectiveIntersect(const vector<Marker> &markers,
// Get the cameras to use for the intersection.
vector<Mat34> cameras;
for (int i = 0; i < markers.size(); ++i) {
- ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image);
+ ProjectiveCamera* camera = reconstruction->CameraForImage(markers[i].image);
cameras.push_back(camera->P);
}
@@ -232,16 +232,16 @@ bool ProjectiveIntersect(const vector<Marker> &markers,
Solver solver(triangulate_cost);
Solver::Results results = solver.minimize(params, &X);
- (void) results; // TODO(keir): Ensure results are good.
+ (void)results; // TODO(keir): Ensure results are good.
// Try projecting the point; make sure it's in front of everyone.
for (int i = 0; i < cameras.size(); ++i) {
- const ProjectiveCamera &camera =
+ const ProjectiveCamera& camera =
*reconstruction->CameraForImage(markers[i].image);
Vec3 x = camera.P * X;
if (x(2) < 0) {
- LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
- << ": " << x.transpose();
+ LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image << ": "
+ << x.transpose();
}
}
diff --git a/intern/libmv/libmv/simple_pipeline/intersect.h b/intern/libmv/libmv/simple_pipeline/intersect.h
index 15d6f998557..aff3ffe66e2 100644
--- a/intern/libmv/libmv/simple_pipeline/intersect.h
+++ b/intern/libmv/libmv/simple_pipeline/intersect.h
@@ -22,8 +22,8 @@
#define LIBMV_SIMPLE_PIPELINE_INTERSECT_H
#include "libmv/base/vector.h"
-#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
@@ -38,7 +38,8 @@ namespace libmv {
\a markers should contain all \link Marker markers \endlink belonging to
tracks visible in all frames.
\a reconstruction should contain the cameras for all frames.
- The new \link Point points \endlink will be inserted in \a reconstruction.
+ The new \link Point points \endlink will be inserted in \a
+ reconstruction.
\note This assumes a calibrated reconstruction, e.g. the markers are
already corrected for camera intrinsics and radial distortion.
@@ -46,8 +47,8 @@ namespace libmv {
\sa EuclideanResect
*/
-bool EuclideanIntersect(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction);
+bool EuclideanIntersect(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction);
/*!
Estimate the homogeneous coordinates of a track by intersecting rays.
@@ -60,7 +61,8 @@ bool EuclideanIntersect(const vector<Marker> &markers,
\a markers should contain all \link Marker markers \endlink belonging to
tracks visible in all frames.
\a reconstruction should contain the cameras for all frames.
- The new \link Point points \endlink will be inserted in \a reconstruction.
+ The new \link Point points \endlink will be inserted in \a
+ reconstruction.
\note This assumes that radial distortion is already corrected for, but
does not assume that e.g. focal length and principal point are
@@ -69,8 +71,8 @@ bool EuclideanIntersect(const vector<Marker> &markers,
\sa Resect
*/
-bool ProjectiveIntersect(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction);
+bool ProjectiveIntersect(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/intersect_test.cc b/intern/libmv/libmv/simple_pipeline/intersect_test.cc
index dd4fdc789af..447cc095cb0 100644
--- a/intern/libmv/libmv/simple_pipeline/intersect_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/intersect_test.cc
@@ -22,10 +22,10 @@
#include <iostream>
-#include "testing/testing.h"
+#include "libmv/logging/logging.h"
#include "libmv/multiview/projection.h"
#include "libmv/numeric/numeric.h"
-#include "libmv/logging/logging.h"
+#include "testing/testing.h"
namespace libmv {
@@ -40,13 +40,15 @@ TEST(Intersect, EuclideanIntersect) {
// 0, 0, 1;
Mat3 R1 = RotationAroundZ(-0.1);
Mat3 R2 = RotationAroundX(-0.1);
- Vec3 t1; t1 << 1, 1, 10;
- Vec3 t2; t2 << -2, -1, 10;
+ Vec3 t1;
+ t1 << 1, 1, 10;
+ Vec3 t2;
+ t2 << -2, -1, 10;
Mat34 P1, P2;
P_From_KRt(K1, R1, t1, &P1);
P_From_KRt(K2, R2, t2, &P2);
- //Mat3 F; FundamentalFromProjections(P1, P2, &F);
+ // Mat3 F; FundamentalFromProjections(P1, P2, &F);
Mat3X X;
X.resize(3, 30);
@@ -68,9 +70,9 @@ TEST(Intersect, EuclideanIntersect) {
reconstruction.InsertCamera(2, R2, t2);
vector<Marker> markers;
- Marker a = { 1, 0, x1.x(), x1.y(), 1.0 };
+ Marker a = {1, 0, x1.x(), x1.y(), 1.0};
markers.push_back(a);
- Marker b = { 2, 0, x2.x(), x2.y(), 1.0 };
+ Marker b = {2, 0, x2.x(), x2.y(), 1.0};
markers.push_back(b);
EuclideanIntersect(markers, &reconstruction);
@@ -78,4 +80,4 @@ TEST(Intersect, EuclideanIntersect) {
EXPECT_NEAR(0, DistanceLInfinity(estimated, expected), 1e-8);
}
}
-} // namespace
+} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc
index 241b5600505..5526d730651 100644
--- a/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc
+++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc
@@ -20,20 +20,20 @@
#include "libmv/simple_pipeline/keyframe_selection.h"
-#include "libmv/numeric/numeric.h"
#include "ceres/ceres.h"
#include "libmv/logging/logging.h"
-#include "libmv/multiview/homography.h"
#include "libmv/multiview/fundamental.h"
-#include "libmv/simple_pipeline/intersect.h"
+#include "libmv/multiview/homography.h"
+#include "libmv/numeric/numeric.h"
#include "libmv/simple_pipeline/bundle.h"
+#include "libmv/simple_pipeline/intersect.h"
#include <Eigen/Eigenvalues>
namespace libmv {
namespace {
-Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) {
+Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics& intrinsics) {
Mat3 T = Mat3::Identity(), S = Mat3::Identity();
T(0, 2) = -intrinsics.principal_point_x();
@@ -56,7 +56,7 @@ Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) {
// (k = 7 for a fundamental matrix or 8 for a homography)
// r is the dimension of the data
// (r = 4 for 2D correspondences between two frames)
-double GRIC(const Vec &e, int d, int k, int r) {
+double GRIC(const Vec& e, int d, int k, int r) {
int n = e.rows();
double lambda1 = log(static_cast<double>(r));
double lambda2 = log(static_cast<double>(r * n));
@@ -89,7 +89,7 @@ double GRIC(const Vec &e, int d, int k, int r) {
//
// TODO(keir): Consider moving this into the numeric code, since this is not
// related to keyframe selection.
-Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix,
+Mat PseudoInverseWithClampedEigenvalues(const Mat& matrix,
int num_eigenvalues_to_clamp) {
Eigen::EigenSolver<Mat> eigen_solver(matrix);
Mat D = eigen_solver.pseudoEigenvalueMatrix();
@@ -112,27 +112,24 @@ Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix,
return V * D * V.inverse();
}
-void FilterZeroWeightMarkersFromTracks(const Tracks &tracks,
- Tracks *filtered_tracks) {
+void FilterZeroWeightMarkersFromTracks(const Tracks& tracks,
+ Tracks* filtered_tracks) {
vector<Marker> all_markers = tracks.AllMarkers();
for (int i = 0; i < all_markers.size(); ++i) {
- Marker &marker = all_markers[i];
+ Marker& marker = all_markers[i];
if (marker.weight != 0.0) {
- filtered_tracks->Insert(marker.image,
- marker.track,
- marker.x,
- marker.y,
- marker.weight);
+ filtered_tracks->Insert(
+ marker.image, marker.track, marker.x, marker.y, marker.weight);
}
}
}
} // namespace
-void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
- const CameraIntrinsics &intrinsics,
- vector<int> &keyframes) {
+void SelectKeyframesBasedOnGRICAndVariance(const Tracks& _tracks,
+ const CameraIntrinsics& intrinsics,
+ vector<int>& keyframes) {
// Mirza Tahir Ahmed, Matthew N. Dailey
// Robust key frame extraction for 3D reconstruction from video streams
//
@@ -172,23 +169,21 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
candidate_image <= max_image;
candidate_image++) {
// Conjunction of all markers from both keyframes
- vector<Marker> all_markers =
- filtered_tracks.MarkersInBothImages(current_keyframe,
- candidate_image);
+ vector<Marker> all_markers = filtered_tracks.MarkersInBothImages(
+ current_keyframe, candidate_image);
// Match keypoints between frames current_keyframe and candidate_image
vector<Marker> tracked_markers =
- filtered_tracks.MarkersForTracksInBothImages(current_keyframe,
- candidate_image);
+ filtered_tracks.MarkersForTracksInBothImages(current_keyframe,
+ candidate_image);
// Correspondences in normalized space
Mat x1, x2;
CoordinatesForMarkersInImage(tracked_markers, current_keyframe, &x1);
CoordinatesForMarkersInImage(tracked_markers, candidate_image, &x2);
- LG << "Found " << x1.cols()
- << " correspondences between " << current_keyframe
- << " and " << candidate_image;
+ LG << "Found " << x1.cols() << " correspondences between "
+ << current_keyframe << " and " << candidate_image;
// Not enough points to construct fundamental matrix
if (x1.cols() < 8 || x2.cols() < 8)
@@ -199,9 +194,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
int Tf = all_markers.size();
double Rc = static_cast<double>(Tc) / Tf;
- LG << "Correspondence between " << current_keyframe
- << " and " << candidate_image
- << ": " << Rc;
+ LG << "Correspondence between " << current_keyframe << " and "
+ << candidate_image << ": " << Rc;
if (Rc < Tmin || Rc > Tmax)
continue;
@@ -210,19 +204,15 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
// Estimate homography using default options.
EstimateHomographyOptions estimate_homography_options;
- EstimateHomography2DFromCorrespondences(x1,
- x2,
- estimate_homography_options,
- &H);
+ EstimateHomography2DFromCorrespondences(
+ x1, x2, estimate_homography_options, &H);
// Convert homography to original pixel space.
H = N_inverse * H * N;
EstimateFundamentalOptions estimate_fundamental_options;
- EstimateFundamentalFromCorrespondences(x1,
- x2,
- estimate_fundamental_options,
- &F);
+ EstimateFundamentalFromCorrespondences(
+ x1, x2, estimate_fundamental_options, &F);
// Convert fundamental to original pixel space.
F = N_inverse * F * N;
@@ -238,11 +228,11 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
for (int i = 0; i < x1.cols(); i++) {
Vec2 current_x1, current_x2;
- intrinsics.NormalizedToImageSpace(x1(0, i), x1(1, i),
- &current_x1(0), &current_x1(1));
+ intrinsics.NormalizedToImageSpace(
+ x1(0, i), x1(1, i), &current_x1(0), &current_x1(1));
- intrinsics.NormalizedToImageSpace(x2(0, i), x2(1, i),
- &current_x2(0), &current_x2(1));
+ intrinsics.NormalizedToImageSpace(
+ x2(0, i), x2(1, i), &current_x2(0), &current_x2(1));
H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2);
F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2);
@@ -255,10 +245,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
double GRIC_H = GRIC(H_e, 2, 8, 4);
double GRIC_F = GRIC(F_e, 3, 7, 4);
- LG << "GRIC values for frames " << current_keyframe
- << " and " << candidate_image
- << ", H-GRIC: " << GRIC_H
- << ", F-GRIC: " << GRIC_F;
+ LG << "GRIC values for frames " << current_keyframe << " and "
+ << candidate_image << ", H-GRIC: " << GRIC_H << ", F-GRIC: " << GRIC_F;
if (GRIC_H <= GRIC_F)
continue;
@@ -295,23 +283,19 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
Vec3 t;
Mat3 K = Mat3::Identity();
- if (!MotionFromEssentialAndCorrespondence(E,
- K, x1.col(0),
- K, x2.col(0),
- &R, &t)) {
+ if (!MotionFromEssentialAndCorrespondence(
+ E, K, x1.col(0), K, x2.col(0), &R, &t)) {
LG << "Failed to compute R and t from E and K";
continue;
}
- LG << "Camera transform between frames " << current_keyframe
- << " and " << candidate_image
- << ":\nR:\n" << R
- << "\nt:" << t.transpose();
+ LG << "Camera transform between frames " << current_keyframe << " and "
+ << candidate_image << ":\nR:\n"
+ << R << "\nt:" << t.transpose();
// First camera is identity, second one is relative to it
- reconstruction.InsertCamera(current_keyframe,
- Mat3::Identity(),
- Vec3::Zero());
+ reconstruction.InsertCamera(
+ current_keyframe, Mat3::Identity(), Vec3::Zero());
reconstruction.InsertCamera(candidate_image, R, t);
// Reconstruct 3D points
@@ -349,7 +333,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
}
double success_intersects_factor =
- (double) intersects_success / intersects_total;
+ (double)intersects_success / intersects_total;
if (success_intersects_factor < success_intersects_factor_best) {
LG << "Skip keyframe candidate because of "
@@ -372,7 +356,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
&empty_intrinsics,
&evaluation);
- Mat &jacobian = evaluation.jacobian;
+ Mat& jacobian = evaluation.jacobian;
Mat JT_J = jacobian.transpose() * jacobian;
// There are 7 degrees of freedom, so clamp them out.
@@ -380,10 +364,10 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
Mat temp_derived = JT_J * JT_J_inv * JT_J;
bool is_inversed = (temp_derived - JT_J).cwiseAbs2().sum() <
- 1e-4 * std::min(temp_derived.cwiseAbs2().sum(),
- JT_J.cwiseAbs2().sum());
+ 1e-4 * std::min(temp_derived.cwiseAbs2().sum(),
+ JT_J.cwiseAbs2().sum());
- LG << "Check on inversed: " << (is_inversed ? "true" : "false" )
+ LG << "Check on inversed: " << (is_inversed ? "true" : "false")
<< ", det(JT_J): " << JT_J.determinant();
if (!is_inversed) {
@@ -400,8 +384,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks,
double Sc = static_cast<double>(I + A) / Square(3 * I) * Sigma_P.trace();
- LG << "Expected estimation error between "
- << current_keyframe << " and "
+ LG << "Expected estimation error between " << current_keyframe << " and "
<< candidate_image << ": " << Sc;
// Pairing with a lower Sc indicates a better choice
diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection.h b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h
index 25253af32fe..a1b3910abd4 100644
--- a/intern/libmv/libmv/simple_pipeline/keyframe_selection.h
+++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h
@@ -22,8 +22,8 @@
#define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
#include "libmv/base/vector.h"
-#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
+#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
@@ -43,10 +43,9 @@ namespace libmv {
// \param intrinsics: is camera intrinsics.
// \param keyframes: will contain all images number which are considered
// good to be used for reconstruction.
-void SelectKeyframesBasedOnGRICAndVariance(
- const Tracks &tracks,
- const CameraIntrinsics &intrinsics,
- vector<int> &keyframes);
+void SelectKeyframesBasedOnGRICAndVariance(const Tracks& tracks,
+ const CameraIntrinsics& intrinsics,
+ vector<int>& keyframes);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
index 9d88362cc88..983349c0c5a 100644
--- a/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
@@ -1,15 +1,15 @@
// Copyright (c) 2011 libmv authors.
-//
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -20,9 +20,9 @@
#include "libmv/simple_pipeline/keyframe_selection.h"
-#include "testing/testing.h"
-#include "libmv/simple_pipeline/camera_intrinsics.h"
#include "libmv/logging/logging.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
+#include "testing/testing.h"
namespace libmv {
@@ -30,7 +30,7 @@ namespace libmv {
// Should not be keyframe
TEST(KeyframeSelection, SyntheticNeighborFrame) {
PolynomialCameraIntrinsics intrinsics;
- intrinsics.SetFocalLength(900.0,900.0);
+ intrinsics.SetFocalLength(900.0, 900.0);
intrinsics.SetPrincipalPoint(640.0, 540.0);
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
@@ -66,25 +66,56 @@ TEST(KeyframeSelection, FabrikEingangNeighborFrames) {
intrinsics.SetPrincipalPoint(960.000, 544.000);
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
- Marker markers[] = {
- {1, 0, 737.599983, 646.397594, 1.0}, {2, 0, 737.906628, 648.113327, 1.0}, {1, 1, 863.045425, 646.081905, 1.0},
- {2, 1, 863.339767, 647.650040, 1.0}, {1, 2, 736.959972, 574.080151, 1.0}, {2, 2, 737.217350, 575.604900, 1.0},
- {1, 3, 864.097424, 573.374908, 1.0}, {2, 3, 864.383469, 574.900307, 1.0}, {1, 4, 789.429073, 631.677521, 1.0},
- {2, 4, 789.893131, 633.124451, 1.0}, {1, 5, 791.051960, 573.442028, 1.0}, {2, 5, 791.336575, 575.088890, 1.0},
- {1, 6, 738.973961, 485.130308, 1.0}, {2, 6, 739.435501, 486.734207, 1.0}, {1, 7, 862.403240, 514.866074, 1.0},
- {2, 7, 862.660618, 516.413261, 1.0}, {1, 8, 802.240162, 485.759838, 1.0}, {2, 8, 802.602253, 487.432899, 1.0},
- {1, 9, 754.340630, 500.624559, 1.0}, {2, 9, 754.559956, 502.079920, 1.0}, {1, 10, 849.398689, 484.480545, 1.0},
- {2, 10, 849.599934, 486.079937, 1.0}, {1, 11, 788.803768, 515.924391, 1.0}, {2, 11, 789.119911, 517.439932, 1.0},
- {1, 12, 838.733940, 558.212688, 1.0}, {2, 12, 839.039898, 559.679916, 1.0}, {1, 13, 760.014782, 575.194466, 1.0},
- {2, 13, 760.319881, 576.639904, 1.0}, {1, 14, 765.321636, 616.015957, 1.0}, {2, 14, 765.759945, 617.599915, 1.0},
- {1, 15, 800.963230, 660.032082, 1.0}, {2, 15, 801.279945, 661.759876, 1.0}, {1, 16, 846.321087, 602.313053, 1.0},
- {2, 16, 846.719913, 603.839878, 1.0}, {1, 17, 864.288311, 616.790524, 1.0}, {2, 17, 864.639931, 618.239918, 1.0},
- {1, 18, 800.006790, 602.573425, 1.0}, {2, 18, 800.319958, 604.159912, 1.0}, {1, 19, 739.026890, 617.944138, 1.0},
- {2, 19, 739.199924, 619.519924, 1.0}, {1, 20, 801.987419, 544.134888, 1.0}, {2, 20, 802.239933, 545.599911, 1.0},
- {1, 21, 753.619823, 542.961300, 1.0}, {2, 21, 753.919945, 544.639874, 1.0}, {1, 22, 787.921257, 499.910206, 1.0},
- {2, 22, 788.159924, 501.439917, 1.0}, {1, 23, 839.095459, 529.287903, 1.0}, {2, 23, 839.359932, 530.879934, 1.0},
- {1, 24, 811.760330, 630.732269, 1.0}, {2, 24, 812.159901, 632.319859, 1.0}
- };
+ Marker markers[] = {{1, 0, 737.599983, 646.397594, 1.0},
+ {2, 0, 737.906628, 648.113327, 1.0},
+ {1, 1, 863.045425, 646.081905, 1.0},
+ {2, 1, 863.339767, 647.650040, 1.0},
+ {1, 2, 736.959972, 574.080151, 1.0},
+ {2, 2, 737.217350, 575.604900, 1.0},
+ {1, 3, 864.097424, 573.374908, 1.0},
+ {2, 3, 864.383469, 574.900307, 1.0},
+ {1, 4, 789.429073, 631.677521, 1.0},
+ {2, 4, 789.893131, 633.124451, 1.0},
+ {1, 5, 791.051960, 573.442028, 1.0},
+ {2, 5, 791.336575, 575.088890, 1.0},
+ {1, 6, 738.973961, 485.130308, 1.0},
+ {2, 6, 739.435501, 486.734207, 1.0},
+ {1, 7, 862.403240, 514.866074, 1.0},
+ {2, 7, 862.660618, 516.413261, 1.0},
+ {1, 8, 802.240162, 485.759838, 1.0},
+ {2, 8, 802.602253, 487.432899, 1.0},
+ {1, 9, 754.340630, 500.624559, 1.0},
+ {2, 9, 754.559956, 502.079920, 1.0},
+ {1, 10, 849.398689, 484.480545, 1.0},
+ {2, 10, 849.599934, 486.079937, 1.0},
+ {1, 11, 788.803768, 515.924391, 1.0},
+ {2, 11, 789.119911, 517.439932, 1.0},
+ {1, 12, 838.733940, 558.212688, 1.0},
+ {2, 12, 839.039898, 559.679916, 1.0},
+ {1, 13, 760.014782, 575.194466, 1.0},
+ {2, 13, 760.319881, 576.639904, 1.0},
+ {1, 14, 765.321636, 616.015957, 1.0},
+ {2, 14, 765.759945, 617.599915, 1.0},
+ {1, 15, 800.963230, 660.032082, 1.0},
+ {2, 15, 801.279945, 661.759876, 1.0},
+ {1, 16, 846.321087, 602.313053, 1.0},
+ {2, 16, 846.719913, 603.839878, 1.0},
+ {1, 17, 864.288311, 616.790524, 1.0},
+ {2, 17, 864.639931, 618.239918, 1.0},
+ {1, 18, 800.006790, 602.573425, 1.0},
+ {2, 18, 800.319958, 604.159912, 1.0},
+ {1, 19, 739.026890, 617.944138, 1.0},
+ {2, 19, 739.199924, 619.519924, 1.0},
+ {1, 20, 801.987419, 544.134888, 1.0},
+ {2, 20, 802.239933, 545.599911, 1.0},
+ {1, 21, 753.619823, 542.961300, 1.0},
+ {2, 21, 753.919945, 544.639874, 1.0},
+ {1, 22, 787.921257, 499.910206, 1.0},
+ {2, 22, 788.159924, 501.439917, 1.0},
+ {1, 23, 839.095459, 529.287903, 1.0},
+ {2, 23, 839.359932, 530.879934, 1.0},
+ {1, 24, 811.760330, 630.732269, 1.0},
+ {2, 24, 812.159901, 632.319859, 1.0}};
int num_markers = sizeof(markers) / sizeof(Marker);
Tracks tracks;
@@ -108,18 +139,34 @@ TEST(KeyframeSelection, FabrikEingangFarFrames) {
intrinsics.SetPrincipalPoint(960.000, 544.000);
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
- Marker markers[] = {
- {1, 0, 369.459200, 619.315258, 1.0}, {2, 0, 279.677496, 722.086842, 1.0}, {1, 1, 376.831970, 370.278397, 1.0},
- {2, 1, 221.695247, 460.065418, 1.0}, {1, 2, 1209.139023, 567.705605, 1.0}, {2, 2, 1080.760117, 659.230083, 1.0},
- {1, 3, 1643.495750, 903.620453, 1.0}, {2, 3, 1618.405037, 1015.374908, 1.0}, {1, 4, 1494.849815, 425.302460, 1.0},
- {2, 4, 1457.467575, 514.727587, 1.0}, {1, 5, 1794.637299, 328.728609, 1.0}, {2, 5, 1742.161446, 408.988636, 1.0},
- {1, 6, 1672.822723, 102.240358, 1.0}, {2, 6, 1539.287224, 153.536892, 1.0}, {1, 7, 1550.843925, 53.424943, 1.0},
- {2, 7, 1385.579109, 96.450085, 1.0}, {1, 8, 852.953281, 465.399578, 1.0}, {2, 8, 779.404564, 560.091843, 1.0},
- {1, 9, 906.853752, 299.827040, 1.0}, {2, 9, 786.923218, 385.570770, 1.0}, {1, 10, 406.322966, 87.556041, 1.0},
- {2, 10, 140.339413, 150.877481, 1.0}, {1, 11, 254.811573, 851.296478, 1.0}, {2, 11, 94.478302, 969.350189, 1.0},
- {1, 12, 729.087868, 806.092758, 1.0}, {2, 12, 606.212139, 919.876560, 1.0}, {1, 13, 1525.719452, 920.398083, 1.0},
- {2, 13, 1495.579720, 1031.971218, 1.0}
- };
+ Marker markers[] = {{1, 0, 369.459200, 619.315258, 1.0},
+ {2, 0, 279.677496, 722.086842, 1.0},
+ {1, 1, 376.831970, 370.278397, 1.0},
+ {2, 1, 221.695247, 460.065418, 1.0},
+ {1, 2, 1209.139023, 567.705605, 1.0},
+ {2, 2, 1080.760117, 659.230083, 1.0},
+ {1, 3, 1643.495750, 903.620453, 1.0},
+ {2, 3, 1618.405037, 1015.374908, 1.0},
+ {1, 4, 1494.849815, 425.302460, 1.0},
+ {2, 4, 1457.467575, 514.727587, 1.0},
+ {1, 5, 1794.637299, 328.728609, 1.0},
+ {2, 5, 1742.161446, 408.988636, 1.0},
+ {1, 6, 1672.822723, 102.240358, 1.0},
+ {2, 6, 1539.287224, 153.536892, 1.0},
+ {1, 7, 1550.843925, 53.424943, 1.0},
+ {2, 7, 1385.579109, 96.450085, 1.0},
+ {1, 8, 852.953281, 465.399578, 1.0},
+ {2, 8, 779.404564, 560.091843, 1.0},
+ {1, 9, 906.853752, 299.827040, 1.0},
+ {2, 9, 786.923218, 385.570770, 1.0},
+ {1, 10, 406.322966, 87.556041, 1.0},
+ {2, 10, 140.339413, 150.877481, 1.0},
+ {1, 11, 254.811573, 851.296478, 1.0},
+ {2, 11, 94.478302, 969.350189, 1.0},
+ {1, 12, 729.087868, 806.092758, 1.0},
+ {2, 12, 606.212139, 919.876560, 1.0},
+ {1, 13, 1525.719452, 920.398083, 1.0},
+ {2, 13, 1495.579720, 1031.971218, 1.0}};
int num_markers = sizeof(markers) / sizeof(Marker);
Tracks tracks;
@@ -144,17 +191,35 @@ TEST(KeyframeSelection, CopterManualKeyFrames) {
intrinsics.SetRadialDistortion(-0.08590, 0.0, 0.0);
Marker markers[] = {
- {1, 0, 645.792694, 403.115931, 1.0}, {2, 0, 630.641174, 307.996409, 1.0}, {1, 1, 783.469086, 403.904328, 1.0},
- {2, 1, 766.001129, 308.998225, 1.0}, {1, 2, 650.000000, 160.000001, 1.0}, {1, 3, 785.225906, 158.619039, 1.0},
- {2, 3, 767.526474, 70.449695, 1.0}, {1, 4, 290.640526, 382.335634, 1.0}, {2, 4, 273.001728, 86.993319, 1.0},
- {1, 5, 291.162739, 410.602684, 1.0}, {2, 5, 273.287849, 111.937487, 1.0}, {1, 6, 136.919317, 349.895797, 1.0},
- {1, 7, 490.844345, 47.572222, 1.0}, {1, 8, 454.406433, 488.935761, 1.0}, {1, 9, 378.655815, 618.522248, 1.0},
- {2, 9, 357.061806, 372.265077, 1.0}, {1, 10, 496.011391, 372.668824, 1.0}, {2, 10, 477.979164, 222.986112, 1.0},
- {1, 11, 680.060272, 256.103625, 1.0}, {2, 11, 670.587540, 204.830453, 1.0}, {1, 12, 1070.817108, 218.775322, 1.0},
- {2, 12, 1046.129913, 128.969783, 1.0}, {1, 14, 242.516403, 596.048512, 1.0}, {2, 14, 224.182606, 248.272154, 1.0},
- {1, 15, 613.936272, 287.519073, 1.0}, {2, 15, 600.467644, 196.085722, 1.0}, {1, 31, 844.637451, 256.354315, 1.0},
+ {1, 0, 645.792694, 403.115931, 1.0},
+ {2, 0, 630.641174, 307.996409, 1.0},
+ {1, 1, 783.469086, 403.904328, 1.0},
+ {2, 1, 766.001129, 308.998225, 1.0},
+ {1, 2, 650.000000, 160.000001, 1.0},
+ {1, 3, 785.225906, 158.619039, 1.0},
+ {2, 3, 767.526474, 70.449695, 1.0},
+ {1, 4, 290.640526, 382.335634, 1.0},
+ {2, 4, 273.001728, 86.993319, 1.0},
+ {1, 5, 291.162739, 410.602684, 1.0},
+ {2, 5, 273.287849, 111.937487, 1.0},
+ {1, 6, 136.919317, 349.895797, 1.0},
+ {1, 7, 490.844345, 47.572222, 1.0},
+ {1, 8, 454.406433, 488.935761, 1.0},
+ {1, 9, 378.655815, 618.522248, 1.0},
+ {2, 9, 357.061806, 372.265077, 1.0},
+ {1, 10, 496.011391, 372.668824, 1.0},
+ {2, 10, 477.979164, 222.986112, 1.0},
+ {1, 11, 680.060272, 256.103625, 1.0},
+ {2, 11, 670.587540, 204.830453, 1.0},
+ {1, 12, 1070.817108, 218.775322, 1.0},
+ {2, 12, 1046.129913, 128.969783, 1.0},
+ {1, 14, 242.516403, 596.048512, 1.0},
+ {2, 14, 224.182606, 248.272154, 1.0},
+ {1, 15, 613.936272, 287.519073, 1.0},
+ {2, 15, 600.467644, 196.085722, 1.0},
+ {1, 31, 844.637451, 256.354315, 1.0},
{2, 31, 823.200150, 165.714952, 1.0},
- };
+ };
int num_markers = sizeof(markers) / sizeof(Marker);
Tracks tracks;
@@ -180,52 +245,140 @@ TEST(KeyframeSelection, ElevatorManualKeyframesFrames) {
intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0);
Marker markers[] = {
- {1, 2, 1139.861412, 1034.634984, 1.0}, {2, 2, 1143.512192, 1065.355718, 1.0}, {1, 3, 1760.821953, 644.658036, 1.0},
- {2, 3, 1770.901108, 697.899928, 1.0}, {1, 4, 858.071823, 1068.520746, 1.0}, {1, 6, 1633.952408, 797.050145, 1.0},
- {2, 6, 1642.508469, 849.157140, 1.0}, {1, 8, 1716.695824, 451.805491, 1.0}, {2, 8, 1726.513939, 502.095687, 1.0},
- {1, 9, 269.577627, 724.986935, 1.0}, {2, 9, 269.424820, 764.154246, 1.0}, {1, 10, 1891.321907, 706.948843, 1.0},
- {2, 10, 1903.338547, 766.068377, 1.0}, {1, 12, 1806.227074, 956.089604, 1.0}, {2, 12, 1816.619568, 1013.767376, 1.0},
- {1, 14, 269.544153, 1002.333570, 1.0}, {2, 14, 269.367542, 1043.509254, 1.0}, {1, 15, 1402.772141, 281.392962, 1.0},
- {2, 15, 1409.089165, 318.731629, 1.0}, {1, 16, 195.877233, 919.454341, 1.0}, {2, 16, 192.531109, 997.367899, 1.0},
- {1, 17, 1789.584045, 120.036661, 1.0}, {2, 17, 1800.391846, 167.822964, 1.0}, {1, 18, 999.363213, 765.004807, 1.0},
- {2, 18, 1002.345772, 790.560122, 1.0}, {1, 19, 647.342491, 1044.805727, 1.0}, {2, 19, 649.328041, 1058.682940, 1.0},
- {1, 20, 1365.486832, 440.901829, 1.0}, {2, 20, 1371.413040, 477.888730, 1.0}, {1, 21, 1787.125282, 301.431606, 1.0},
- {2, 21, 1798.527260, 355.224531, 1.0}, {1, 22, 1257.805824, 932.797258, 1.0}, {2, 22, 1263.017578, 969.376774, 1.0},
- {1, 23, 961.969528, 843.148112, 1.0}, {2, 23, 964.869461, 868.587620, 1.0}, {1, 24, 158.076110, 1052.643592, 1.0},
- {1, 25, 1072.884521, 1005.296981, 1.0}, {2, 25, 1076.091156, 1032.776856, 1.0}, {1, 26, 1107.656937, 526.577228, 1.0},
- {2, 26, 1111.618423, 555.524454, 1.0}, {1, 27, 1416.410751, 529.857581, 1.0}, {2, 27, 1422.663574, 570.025957, 1.0},
- {1, 28, 1498.673630, 1005.453086, 1.0}, {2, 28, 1505.381813, 1051.827149, 1.0}, {1, 29, 1428.647804, 652.473629, 1.0},
- {2, 29, 1434.898224, 692.715390, 1.0}, {1, 30, 1332.318764, 503.673599, 1.0}, {2, 30, 1338.000069, 540.507967, 1.0},
- {1, 32, 1358.642693, 709.837904, 1.0}, {2, 32, 1364.231529, 748.678265, 1.0}, {1, 33, 1850.911560, 460.475668, 1.0},
- {2, 33, 1862.221413, 512.797347, 1.0}, {1, 34, 1226.117821, 607.053959, 1.0}, {2, 34, 1230.736084, 641.091449, 1.0},
- {1, 35, 619.598236, 523.341744, 1.0}, {2, 35, 621.601124, 554.453287, 1.0}, {1, 36, 956.591492, 958.223183, 1.0},
- {2, 36, 959.289265, 983.289263, 1.0}, {1, 37, 1249.922218, 419.095856, 1.0}, {2, 37, 1255.005913, 452.556177, 1.0},
- {1, 39, 1300.528450, 386.251166, 1.0}, {2, 39, 1305.957413, 420.185595, 1.0}, {1, 40, 1128.689919, 972.558346, 1.0},
- {2, 40, 1132.413712, 1003.984737, 1.0}, {1, 41, 503.304749, 1053.504388, 1.0}, {2, 41, 505.019703, 1069.175613, 1.0},
- {1, 42, 1197.352982, 472.681564, 1.0}, {2, 42, 1201.910706, 503.459880, 1.0}, {1, 43, 1794.391022, 383.911400, 1.0},
- {2, 43, 1805.324135, 436.116468, 1.0}, {1, 44, 789.641418, 1058.045647, 1.0}, {1, 45, 1376.575241, 928.714979, 1.0},
- {2, 45, 1381.995850, 969.511957, 1.0}, {1, 46, 1598.023567, 93.975592, 1.0}, {2, 46, 1606.937141, 136.827035, 1.0},
- {1, 47, 1455.550232, 762.128685, 1.0}, {2, 47, 1462.014313, 805.164878, 1.0}, {1, 48, 1357.123489, 354.460326, 1.0},
- {2, 48, 1363.071899, 390.363121, 1.0}, {1, 49, 939.792652, 781.549895, 1.0}, {2, 49, 942.802620, 806.164012, 1.0},
- {1, 50, 1380.251083, 805.948620, 1.0}, {2, 50, 1385.637932, 845.592098, 1.0}, {1, 51, 1021.769943, 1049.802361, 1.0},
- {1, 52, 1065.634918, 608.099055, 1.0}, {2, 52, 1069.142189, 635.361736, 1.0}, {1, 53, 624.324188, 463.202863, 1.0},
- {2, 53, 626.395454, 494.994088, 1.0}, {1, 54, 1451.459885, 881.557624, 1.0}, {2, 54, 1457.679634, 924.345531, 1.0},
- {1, 55, 1201.885986, 1057.079022, 1.0}, {1, 56, 581.157532, 947.661438, 1.0}, {2, 56, 583.242359, 960.831449, 1.0},
- {1, 58, 513.593102, 954.175858, 1.0}, {2, 58, 515.470047, 971.309574, 1.0}, {1, 59, 928.069038, 901.774421, 1.0},
- {2, 59, 930.847950, 925.613744, 1.0}, {1, 60, 1065.860023, 740.395389, 1.0}, {2, 60, 1069.484253, 768.971086, 1.0},
- {1, 61, 990.479393, 906.264632, 1.0}, {2, 61, 993.217506, 933.088803, 1.0}, {1, 62, 1776.196747, 776.278453, 1.0},
- {2, 62, 1786.292496, 831.136880, 1.0}, {1, 63, 834.454365, 1012.449725, 1.0}, {2, 63, 836.868324, 1033.451807, 1.0},
- {1, 64, 1355.190697, 869.184809, 1.0}, {2, 64, 1360.736618, 909.773347, 1.0}, {1, 65, 702.072487, 897.519686, 1.0},
- {2, 65, 704.203377, 911.931131, 1.0}, {1, 66, 1214.022903, 856.199934, 1.0}, {2, 66, 1218.109016, 890.753052, 1.0},
- {1, 67, 327.676048, 236.814036, 1.0}, {2, 67, 328.335285, 277.251878, 1.0}, {1, 68, 289.064083, 454.793912, 1.0},
- {2, 68, 288.651924, 498.882444, 1.0}, {1, 69, 1626.240692, 278.374350, 1.0}, {2, 69, 1634.131508, 315.853672, 1.0},
- {1, 70, 1245.375710, 734.862142, 1.0}, {2, 70, 1250.047417, 769.670885, 1.0}, {1, 71, 497.015305, 510.718904, 1.0},
- {2, 71, 498.682308, 541.070201, 1.0}, {1, 72, 1280.542030, 153.939185, 1.0}, {2, 72, 1286.993637, 198.436196, 1.0},
- {1, 73, 1534.748840, 138.601043, 1.0}, {2, 73, 1542.961349, 180.170819, 1.0}, {1, 74, 1477.412682, 200.608061, 1.0},
- {2, 74, 1484.683914, 240.413260, 1.0}, {1, 76, 450.637321, 407.279642, 1.0}, {2, 76, 451.695642, 441.666291, 1.0},
- {1, 78, 246.981239, 220.786298, 1.0}, {2, 78, 244.524879, 290.016564, 1.0}, {1, 79, 36.696489, 420.023407, 1.0},
+ {1, 2, 1139.861412, 1034.634984, 1.0},
+ {2, 2, 1143.512192, 1065.355718, 1.0},
+ {1, 3, 1760.821953, 644.658036, 1.0},
+ {2, 3, 1770.901108, 697.899928, 1.0},
+ {1, 4, 858.071823, 1068.520746, 1.0},
+ {1, 6, 1633.952408, 797.050145, 1.0},
+ {2, 6, 1642.508469, 849.157140, 1.0},
+ {1, 8, 1716.695824, 451.805491, 1.0},
+ {2, 8, 1726.513939, 502.095687, 1.0},
+ {1, 9, 269.577627, 724.986935, 1.0},
+ {2, 9, 269.424820, 764.154246, 1.0},
+ {1, 10, 1891.321907, 706.948843, 1.0},
+ {2, 10, 1903.338547, 766.068377, 1.0},
+ {1, 12, 1806.227074, 956.089604, 1.0},
+ {2, 12, 1816.619568, 1013.767376, 1.0},
+ {1, 14, 269.544153, 1002.333570, 1.0},
+ {2, 14, 269.367542, 1043.509254, 1.0},
+ {1, 15, 1402.772141, 281.392962, 1.0},
+ {2, 15, 1409.089165, 318.731629, 1.0},
+ {1, 16, 195.877233, 919.454341, 1.0},
+ {2, 16, 192.531109, 997.367899, 1.0},
+ {1, 17, 1789.584045, 120.036661, 1.0},
+ {2, 17, 1800.391846, 167.822964, 1.0},
+ {1, 18, 999.363213, 765.004807, 1.0},
+ {2, 18, 1002.345772, 790.560122, 1.0},
+ {1, 19, 647.342491, 1044.805727, 1.0},
+ {2, 19, 649.328041, 1058.682940, 1.0},
+ {1, 20, 1365.486832, 440.901829, 1.0},
+ {2, 20, 1371.413040, 477.888730, 1.0},
+ {1, 21, 1787.125282, 301.431606, 1.0},
+ {2, 21, 1798.527260, 355.224531, 1.0},
+ {1, 22, 1257.805824, 932.797258, 1.0},
+ {2, 22, 1263.017578, 969.376774, 1.0},
+ {1, 23, 961.969528, 843.148112, 1.0},
+ {2, 23, 964.869461, 868.587620, 1.0},
+ {1, 24, 158.076110, 1052.643592, 1.0},
+ {1, 25, 1072.884521, 1005.296981, 1.0},
+ {2, 25, 1076.091156, 1032.776856, 1.0},
+ {1, 26, 1107.656937, 526.577228, 1.0},
+ {2, 26, 1111.618423, 555.524454, 1.0},
+ {1, 27, 1416.410751, 529.857581, 1.0},
+ {2, 27, 1422.663574, 570.025957, 1.0},
+ {1, 28, 1498.673630, 1005.453086, 1.0},
+ {2, 28, 1505.381813, 1051.827149, 1.0},
+ {1, 29, 1428.647804, 652.473629, 1.0},
+ {2, 29, 1434.898224, 692.715390, 1.0},
+ {1, 30, 1332.318764, 503.673599, 1.0},
+ {2, 30, 1338.000069, 540.507967, 1.0},
+ {1, 32, 1358.642693, 709.837904, 1.0},
+ {2, 32, 1364.231529, 748.678265, 1.0},
+ {1, 33, 1850.911560, 460.475668, 1.0},
+ {2, 33, 1862.221413, 512.797347, 1.0},
+ {1, 34, 1226.117821, 607.053959, 1.0},
+ {2, 34, 1230.736084, 641.091449, 1.0},
+ {1, 35, 619.598236, 523.341744, 1.0},
+ {2, 35, 621.601124, 554.453287, 1.0},
+ {1, 36, 956.591492, 958.223183, 1.0},
+ {2, 36, 959.289265, 983.289263, 1.0},
+ {1, 37, 1249.922218, 419.095856, 1.0},
+ {2, 37, 1255.005913, 452.556177, 1.0},
+ {1, 39, 1300.528450, 386.251166, 1.0},
+ {2, 39, 1305.957413, 420.185595, 1.0},
+ {1, 40, 1128.689919, 972.558346, 1.0},
+ {2, 40, 1132.413712, 1003.984737, 1.0},
+ {1, 41, 503.304749, 1053.504388, 1.0},
+ {2, 41, 505.019703, 1069.175613, 1.0},
+ {1, 42, 1197.352982, 472.681564, 1.0},
+ {2, 42, 1201.910706, 503.459880, 1.0},
+ {1, 43, 1794.391022, 383.911400, 1.0},
+ {2, 43, 1805.324135, 436.116468, 1.0},
+ {1, 44, 789.641418, 1058.045647, 1.0},
+ {1, 45, 1376.575241, 928.714979, 1.0},
+ {2, 45, 1381.995850, 969.511957, 1.0},
+ {1, 46, 1598.023567, 93.975592, 1.0},
+ {2, 46, 1606.937141, 136.827035, 1.0},
+ {1, 47, 1455.550232, 762.128685, 1.0},
+ {2, 47, 1462.014313, 805.164878, 1.0},
+ {1, 48, 1357.123489, 354.460326, 1.0},
+ {2, 48, 1363.071899, 390.363121, 1.0},
+ {1, 49, 939.792652, 781.549895, 1.0},
+ {2, 49, 942.802620, 806.164012, 1.0},
+ {1, 50, 1380.251083, 805.948620, 1.0},
+ {2, 50, 1385.637932, 845.592098, 1.0},
+ {1, 51, 1021.769943, 1049.802361, 1.0},
+ {1, 52, 1065.634918, 608.099055, 1.0},
+ {2, 52, 1069.142189, 635.361736, 1.0},
+ {1, 53, 624.324188, 463.202863, 1.0},
+ {2, 53, 626.395454, 494.994088, 1.0},
+ {1, 54, 1451.459885, 881.557624, 1.0},
+ {2, 54, 1457.679634, 924.345531, 1.0},
+ {1, 55, 1201.885986, 1057.079022, 1.0},
+ {1, 56, 581.157532, 947.661438, 1.0},
+ {2, 56, 583.242359, 960.831449, 1.0},
+ {1, 58, 513.593102, 954.175858, 1.0},
+ {2, 58, 515.470047, 971.309574, 1.0},
+ {1, 59, 928.069038, 901.774421, 1.0},
+ {2, 59, 930.847950, 925.613744, 1.0},
+ {1, 60, 1065.860023, 740.395389, 1.0},
+ {2, 60, 1069.484253, 768.971086, 1.0},
+ {1, 61, 990.479393, 906.264632, 1.0},
+ {2, 61, 993.217506, 933.088803, 1.0},
+ {1, 62, 1776.196747, 776.278453, 1.0},
+ {2, 62, 1786.292496, 831.136880, 1.0},
+ {1, 63, 834.454365, 1012.449725, 1.0},
+ {2, 63, 836.868324, 1033.451807, 1.0},
+ {1, 64, 1355.190697, 869.184809, 1.0},
+ {2, 64, 1360.736618, 909.773347, 1.0},
+ {1, 65, 702.072487, 897.519686, 1.0},
+ {2, 65, 704.203377, 911.931131, 1.0},
+ {1, 66, 1214.022903, 856.199934, 1.0},
+ {2, 66, 1218.109016, 890.753052, 1.0},
+ {1, 67, 327.676048, 236.814036, 1.0},
+ {2, 67, 328.335285, 277.251878, 1.0},
+ {1, 68, 289.064083, 454.793912, 1.0},
+ {2, 68, 288.651924, 498.882444, 1.0},
+ {1, 69, 1626.240692, 278.374350, 1.0},
+ {2, 69, 1634.131508, 315.853672, 1.0},
+ {1, 70, 1245.375710, 734.862142, 1.0},
+ {2, 70, 1250.047417, 769.670885, 1.0},
+ {1, 71, 497.015305, 510.718904, 1.0},
+ {2, 71, 498.682308, 541.070201, 1.0},
+ {1, 72, 1280.542030, 153.939185, 1.0},
+ {2, 72, 1286.993637, 198.436196, 1.0},
+ {1, 73, 1534.748840, 138.601043, 1.0},
+ {2, 73, 1542.961349, 180.170819, 1.0},
+ {1, 74, 1477.412682, 200.608061, 1.0},
+ {2, 74, 1484.683914, 240.413260, 1.0},
+ {1, 76, 450.637321, 407.279642, 1.0},
+ {2, 76, 451.695642, 441.666291, 1.0},
+ {1, 78, 246.981239, 220.786298, 1.0},
+ {2, 78, 244.524879, 290.016564, 1.0},
+ {1, 79, 36.696489, 420.023407, 1.0},
{2, 79, 21.364746, 591.245492, 1.0},
- };
+ };
int num_markers = sizeof(markers) / sizeof(Marker);
Tracks tracks;
@@ -249,41 +402,110 @@ TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) {
intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0);
Marker markers[] = {
- {1, 0, 182.999997, 1047.000010, 1.0}, {2, 0, 181.475730, 1052.091079, 1.0}, {3, 0, 181.741562, 1057.893341, 1.0},
- {4, 0, 183.190498, 1068.310440, 1.0}, {1, 1, 271.000013, 666.000009, 1.0}, {2, 1, 270.596180, 668.665760, 1.0},
- {3, 1, 270.523510, 671.559069, 1.0}, {4, 1, 271.856518, 676.818151, 1.0}, {5, 1, 268.989000, 727.051570, 1.0},
- {1, 2, 264.999990, 1018.000031, 1.0}, {2, 2, 264.020061, 1021.157591, 1.0}, {3, 2, 264.606056, 1024.823506, 1.0},
- {4, 2, 266.200933, 1031.168690, 1.0}, {1, 3, 270.000000, 938.000014, 1.0}, {2, 3, 269.022617, 941.153390, 1.0},
- {3, 3, 269.605579, 944.454954, 1.0}, {4, 3, 271.281366, 949.452167, 1.0}, {5, 3, 268.963480, 1004.417453, 1.0},
- {1, 4, 200.999994, 799.000003, 1.0}, {2, 4, 199.841366, 803.891838, 1.0}, {3, 4, 200.262208, 809.323246, 1.0},
- {4, 4, 201.456513, 819.271195, 1.0}, {5, 4, 195.026493, 924.363234, 1.0}, {1, 5, 1775.000038, 49.999998, 1.0},
- {2, 5, 1775.255127, 53.718264, 1.0}, {3, 5, 1776.449890, 55.951670, 1.0}, {4, 5, 1778.815727, 61.923309, 1.0},
- {5, 5, 1790.274124, 123.074923, 1.0}, {1, 6, 164.000001, 927.999988, 1.0}, {2, 6, 162.665462, 933.169527, 1.0},
- {3, 6, 163.067923, 938.577182, 1.0}, {4, 6, 164.370360, 948.840945, 1.0}, {5, 6, 157.199407, 1057.762341, 1.0},
- {1, 7, 618.000011, 477.999998, 1.0}, {2, 7, 617.583504, 480.124243, 1.0}, {3, 7, 618.356495, 482.441897, 1.0},
- {4, 7, 619.792500, 486.428132, 1.0}, {5, 7, 619.546051, 525.222627, 1.0}, {1, 8, 499.999981, 1036.999984, 1.0},
- {2, 8, 499.080162, 1038.720160, 1.0}, {3, 8, 499.949398, 1039.014344, 1.0}, {4, 8, 501.828003, 1041.286647, 1.0},
- {5, 8, 502.777576, 1055.196369, 1.0}, {1, 9, 1587.000046, 31.999999, 1.0}, {2, 9, 1586.988373, 34.635853, 1.0},
- {3, 9, 1588.155899, 37.444186, 1.0}, {4, 9, 1589.973106, 42.492081, 1.0}, {5, 9, 1598.683205, 96.526332, 1.0},
- {1, 10, 622.999992, 416.999999, 1.0}, {2, 10, 622.449017, 419.233485, 1.0}, {3, 10, 623.283234, 421.500703, 1.0},
- {4, 10, 624.620132, 425.537406, 1.0}, {5, 10, 624.290829, 465.078338, 1.0}, {1, 11, 577.999992, 931.999998, 1.0},
- {2, 11, 577.042294, 932.872703, 1.0}, {3, 11, 577.832451, 934.045451, 1.0}, {4, 11, 579.729137, 935.735435, 1.0},
- {5, 11, 580.691242, 948.396256, 1.0}, {1, 12, 510.999985, 931.999998, 1.0}, {2, 12, 510.111237, 933.152146, 1.0},
- {3, 12, 510.797081, 934.454219, 1.0}, {4, 12, 512.647362, 936.595910, 1.0}, {5, 12, 513.247204, 955.144157, 1.0},
- {1, 13, 330.459995, 177.059993, 1.0}, {2, 13, 329.876347, 179.615586, 1.0}, {3, 13, 330.681696, 182.757810, 1.0},
- {4, 13, 331.345053, 187.903853, 1.0}, {5, 13, 327.824135, 239.611639, 1.0}, {1, 14, 291.813097, 388.516195, 1.0},
- {2, 14, 290.984058, 391.382725, 1.0}, {3, 14, 291.526737, 394.778595, 1.0}, {4, 14, 292.763815, 400.310973, 1.0},
- {5, 14, 288.714552, 457.548015, 1.0}, {1, 15, 496.491680, 466.534005, 1.0}, {2, 15, 495.909519, 468.518561, 1.0},
- {3, 15, 496.588383, 470.853596, 1.0}, {4, 15, 497.976780, 474.731458, 1.0}, {5, 15, 496.998882, 512.568694, 1.0},
- {1, 16, 1273.000031, 89.000000, 1.0}, {2, 16, 1272.951965, 92.003637, 1.0}, {3, 16, 1273.934784, 94.972191, 1.0},
- {4, 16, 1275.493584, 100.139952, 1.0}, {5, 16, 1281.003571, 156.880163, 1.0}, {1, 17, 1524.713173, 78.852922, 1.0},
- {2, 17, 1524.782066, 81.427142, 1.0}, {3, 17, 1525.759048, 84.057939, 1.0}, {4, 17, 1527.579689, 88.966550, 1.0},
- {5, 17, 1535.262451, 141.186054, 1.0}, {1, 18, 1509.425011, 94.371824, 1.0}, {1, 19, 451.000013, 357.000003, 1.0},
- {2, 19, 450.354881, 359.312410, 1.0}, {3, 19, 451.107473, 361.837088, 1.0}, {4, 19, 452.186537, 366.318061, 1.0},
- {5, 19, 450.507660, 409.257599, 1.0}, {1, 20, 254.004936, 114.784185, 1.0}, {2, 20, 253.291512, 119.288486, 1.0},
- {3, 20, 253.745584, 124.114957, 1.0}, {4, 20, 254.453287, 132.795120, 1.0}, {5, 20, 246.772242, 225.165337, 1.0},
- {1, 21, 65.262880, 147.889409, 1.0}, {2, 21, 63.634465, 157.656807, 1.0}, {3, 21, 63.306799, 169.067053, 1.0},
- {4, 21, 62.462311, 189.724241, 1.0}, {5, 21, 35.396615, 430.308380, 1.0},
+ {1, 0, 182.999997, 1047.000010, 1.0},
+ {2, 0, 181.475730, 1052.091079, 1.0},
+ {3, 0, 181.741562, 1057.893341, 1.0},
+ {4, 0, 183.190498, 1068.310440, 1.0},
+ {1, 1, 271.000013, 666.000009, 1.0},
+ {2, 1, 270.596180, 668.665760, 1.0},
+ {3, 1, 270.523510, 671.559069, 1.0},
+ {4, 1, 271.856518, 676.818151, 1.0},
+ {5, 1, 268.989000, 727.051570, 1.0},
+ {1, 2, 264.999990, 1018.000031, 1.0},
+ {2, 2, 264.020061, 1021.157591, 1.0},
+ {3, 2, 264.606056, 1024.823506, 1.0},
+ {4, 2, 266.200933, 1031.168690, 1.0},
+ {1, 3, 270.000000, 938.000014, 1.0},
+ {2, 3, 269.022617, 941.153390, 1.0},
+ {3, 3, 269.605579, 944.454954, 1.0},
+ {4, 3, 271.281366, 949.452167, 1.0},
+ {5, 3, 268.963480, 1004.417453, 1.0},
+ {1, 4, 200.999994, 799.000003, 1.0},
+ {2, 4, 199.841366, 803.891838, 1.0},
+ {3, 4, 200.262208, 809.323246, 1.0},
+ {4, 4, 201.456513, 819.271195, 1.0},
+ {5, 4, 195.026493, 924.363234, 1.0},
+ {1, 5, 1775.000038, 49.999998, 1.0},
+ {2, 5, 1775.255127, 53.718264, 1.0},
+ {3, 5, 1776.449890, 55.951670, 1.0},
+ {4, 5, 1778.815727, 61.923309, 1.0},
+ {5, 5, 1790.274124, 123.074923, 1.0},
+ {1, 6, 164.000001, 927.999988, 1.0},
+ {2, 6, 162.665462, 933.169527, 1.0},
+ {3, 6, 163.067923, 938.577182, 1.0},
+ {4, 6, 164.370360, 948.840945, 1.0},
+ {5, 6, 157.199407, 1057.762341, 1.0},
+ {1, 7, 618.000011, 477.999998, 1.0},
+ {2, 7, 617.583504, 480.124243, 1.0},
+ {3, 7, 618.356495, 482.441897, 1.0},
+ {4, 7, 619.792500, 486.428132, 1.0},
+ {5, 7, 619.546051, 525.222627, 1.0},
+ {1, 8, 499.999981, 1036.999984, 1.0},
+ {2, 8, 499.080162, 1038.720160, 1.0},
+ {3, 8, 499.949398, 1039.014344, 1.0},
+ {4, 8, 501.828003, 1041.286647, 1.0},
+ {5, 8, 502.777576, 1055.196369, 1.0},
+ {1, 9, 1587.000046, 31.999999, 1.0},
+ {2, 9, 1586.988373, 34.635853, 1.0},
+ {3, 9, 1588.155899, 37.444186, 1.0},
+ {4, 9, 1589.973106, 42.492081, 1.0},
+ {5, 9, 1598.683205, 96.526332, 1.0},
+ {1, 10, 622.999992, 416.999999, 1.0},
+ {2, 10, 622.449017, 419.233485, 1.0},
+ {3, 10, 623.283234, 421.500703, 1.0},
+ {4, 10, 624.620132, 425.537406, 1.0},
+ {5, 10, 624.290829, 465.078338, 1.0},
+ {1, 11, 577.999992, 931.999998, 1.0},
+ {2, 11, 577.042294, 932.872703, 1.0},
+ {3, 11, 577.832451, 934.045451, 1.0},
+ {4, 11, 579.729137, 935.735435, 1.0},
+ {5, 11, 580.691242, 948.396256, 1.0},
+ {1, 12, 510.999985, 931.999998, 1.0},
+ {2, 12, 510.111237, 933.152146, 1.0},
+ {3, 12, 510.797081, 934.454219, 1.0},
+ {4, 12, 512.647362, 936.595910, 1.0},
+ {5, 12, 513.247204, 955.144157, 1.0},
+ {1, 13, 330.459995, 177.059993, 1.0},
+ {2, 13, 329.876347, 179.615586, 1.0},
+ {3, 13, 330.681696, 182.757810, 1.0},
+ {4, 13, 331.345053, 187.903853, 1.0},
+ {5, 13, 327.824135, 239.611639, 1.0},
+ {1, 14, 291.813097, 388.516195, 1.0},
+ {2, 14, 290.984058, 391.382725, 1.0},
+ {3, 14, 291.526737, 394.778595, 1.0},
+ {4, 14, 292.763815, 400.310973, 1.0},
+ {5, 14, 288.714552, 457.548015, 1.0},
+ {1, 15, 496.491680, 466.534005, 1.0},
+ {2, 15, 495.909519, 468.518561, 1.0},
+ {3, 15, 496.588383, 470.853596, 1.0},
+ {4, 15, 497.976780, 474.731458, 1.0},
+ {5, 15, 496.998882, 512.568694, 1.0},
+ {1, 16, 1273.000031, 89.000000, 1.0},
+ {2, 16, 1272.951965, 92.003637, 1.0},
+ {3, 16, 1273.934784, 94.972191, 1.0},
+ {4, 16, 1275.493584, 100.139952, 1.0},
+ {5, 16, 1281.003571, 156.880163, 1.0},
+ {1, 17, 1524.713173, 78.852922, 1.0},
+ {2, 17, 1524.782066, 81.427142, 1.0},
+ {3, 17, 1525.759048, 84.057939, 1.0},
+ {4, 17, 1527.579689, 88.966550, 1.0},
+ {5, 17, 1535.262451, 141.186054, 1.0},
+ {1, 18, 1509.425011, 94.371824, 1.0},
+ {1, 19, 451.000013, 357.000003, 1.0},
+ {2, 19, 450.354881, 359.312410, 1.0},
+ {3, 19, 451.107473, 361.837088, 1.0},
+ {4, 19, 452.186537, 366.318061, 1.0},
+ {5, 19, 450.507660, 409.257599, 1.0},
+ {1, 20, 254.004936, 114.784185, 1.0},
+ {2, 20, 253.291512, 119.288486, 1.0},
+ {3, 20, 253.745584, 124.114957, 1.0},
+ {4, 20, 254.453287, 132.795120, 1.0},
+ {5, 20, 246.772242, 225.165337, 1.0},
+ {1, 21, 65.262880, 147.889409, 1.0},
+ {2, 21, 63.634465, 157.656807, 1.0},
+ {3, 21, 63.306799, 169.067053, 1.0},
+ {4, 21, 62.462311, 189.724241, 1.0},
+ {5, 21, 35.396615, 430.308380, 1.0},
};
int num_markers = sizeof(markers) / sizeof(Marker);
@@ -304,4 +526,4 @@ TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) {
}
}
-} // namespace libmv
+} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.cc b/intern/libmv/libmv/simple_pipeline/modal_solver.cc
index 687c328b004..845b299e31e 100644
--- a/intern/libmv/libmv/simple_pipeline/modal_solver.cc
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver.cc
@@ -34,7 +34,7 @@
namespace libmv {
namespace {
-void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) {
+void ProjectMarkerOnSphere(const Marker& marker, Vec3& X) {
X(0) = marker.x;
X(1) = marker.y;
X(2) = 1.0;
@@ -42,12 +42,14 @@ void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) {
X *= 5.0 / X.norm();
}
-void ModalSolverLogProgress(ProgressUpdateCallback *update_callback,
- double progress) {
+void ModalSolverLogProgress(ProgressUpdateCallback* update_callback,
+ double progress) {
if (update_callback) {
char message[256];
- snprintf(message, sizeof(message), "Solving progress %d%%",
+ snprintf(message,
+ sizeof(message),
+ "Solving progress %d%%",
(int)(progress * 100));
update_callback->invoke(progress, message);
@@ -58,25 +60,27 @@ struct ModalReprojectionError {
ModalReprojectionError(double observed_x,
double observed_y,
const double weight,
- const Vec3 &bundle)
- : observed_x_(observed_x), observed_y_(observed_y),
- weight_(weight), bundle_(bundle) { }
+ const Vec3& bundle)
+ : observed_x_(observed_x),
+ observed_y_(observed_y),
+ weight_(weight),
+ bundle_(bundle) {}
// TODO(keir): This should support bundling focal length as well.
template <typename T>
bool operator()(const T* quaternion, T* residuals) const {
// Convert bundle position from double to T.
- T X[3] = { T(bundle_(0)), T(bundle_(1)), T(bundle_(2)) };
+ T X[3] = {T(bundle_(0)), T(bundle_(1)), T(bundle_(2))};
// Compute the point position in camera coordinates: x = RX.
T x[3];
// This flips the sense of the quaternion, to adhere to Blender conventions.
T quaternion_inverse[4] = {
- quaternion[0],
- -quaternion[1],
- -quaternion[2],
- -quaternion[3],
+ quaternion[0],
+ -quaternion[1],
+ -quaternion[2],
+ -quaternion[3],
};
ceres::QuaternionRotatePoint(quaternion_inverse, X, x);
@@ -99,9 +103,9 @@ struct ModalReprojectionError {
};
} // namespace
-void ModalSolver(const Tracks &tracks,
- EuclideanReconstruction *reconstruction,
- ProgressUpdateCallback *update_callback) {
+void ModalSolver(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction,
+ ProgressUpdateCallback* update_callback) {
int max_image = tracks.MaxImage();
int max_track = tracks.MaxTrack();
@@ -116,7 +120,7 @@ void ModalSolver(const Tracks &tracks,
for (int image = 0; image <= max_image; ++image) {
vector<Marker> all_markers = tracks.MarkersInImage(image);
- ModalSolverLogProgress(update_callback, (float) image / max_image);
+ ModalSolverLogProgress(update_callback, (float)image / max_image);
// Skip empty images without doing anything.
if (all_markers.size() == 0) {
@@ -133,8 +137,8 @@ void ModalSolver(const Tracks &tracks,
// 3D positions.
Mat x1, x2;
for (int i = 0; i < all_markers.size(); ++i) {
- Marker &marker = all_markers[i];
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ Marker& marker = all_markers[i];
+ EuclideanPoint* point = reconstruction->PointForTrack(marker.track);
if (point) {
Vec3 X;
ProjectMarkerOnSphere(marker, X);
@@ -168,8 +172,7 @@ void ModalSolver(const Tracks &tracks,
ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0));
- LG << "Analytically computed quaternion "
- << quaternion.transpose();
+ LG << "Analytically computed quaternion " << quaternion.transpose();
}
// STEP 2: Refine rotation with Ceres.
@@ -181,17 +184,15 @@ void ModalSolver(const Tracks &tracks,
int num_residuals = 0;
for (int i = 0; i < all_markers.size(); ++i) {
- Marker &marker = all_markers[i];
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ Marker& marker = all_markers[i];
+ EuclideanPoint* point = reconstruction->PointForTrack(marker.track);
if (point && marker.weight != 0.0) {
- problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
- ModalReprojectionError,
- 2, /* num_residuals */
- 4>(new ModalReprojectionError(marker.x,
- marker.y,
- marker.weight,
- point->X)),
+ problem.AddResidualBlock(
+ new ceres::AutoDiffCostFunction<ModalReprojectionError,
+ 2, /* num_residuals */
+ 4>(new ModalReprojectionError(
+ marker.x, marker.y, marker.weight, point->X)),
NULL,
&quaternion(0));
num_residuals++;
diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.h b/intern/libmv/libmv/simple_pipeline/modal_solver.h
index 9801fd21d81..f7ce394b4b2 100644
--- a/intern/libmv/libmv/simple_pipeline/modal_solver.h
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver.h
@@ -21,9 +21,9 @@
#ifndef LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_
#define LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_
-#include "libmv/simple_pipeline/tracks.h"
-#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/callbacks.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
@@ -39,9 +39,9 @@ namespace libmv {
Reconstructed cameras and projected bundles would be added to reconstruction
object.
*/
-void ModalSolver(const Tracks &tracks,
- EuclideanReconstruction *reconstruction,
- ProgressUpdateCallback *update_callback = NULL);
+void ModalSolver(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction,
+ ProgressUpdateCallback* update_callback = NULL);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc
index b4cae8defb2..0acf978e6f5 100644
--- a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc
@@ -20,10 +20,10 @@
#include "libmv/simple_pipeline/modal_solver.h"
-#include "testing/testing.h"
#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
+#include "testing/testing.h"
#include <stdio.h>
@@ -38,14 +38,21 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) {
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
Marker markers[] = {
- {1, 0, 212.172775, 354.713538, 1.0}, {2, 0, 773.468399, 358.735306, 1.0},
- {1, 1, 62.415197, 287.905354, 1.0}, {2, 1, 619.103336, 324.402537, 1.0},
- {1, 2, 206.847939, 237.567925, 1.0}, {2, 2, 737.496986, 247.881383, 1.0},
- {1, 3, 351.743889, 316.415906, 1.0}, {2, 3, 908.779621, 290.703617, 1.0},
- {1, 4, 232.941413, 54.265443, 1.0}, {2, 4, 719.444847, 63.062531, 1.0},
- {1, 5, 96.391611, 119.283537, 1.0}, {2, 5, 611.413136, 160.890715, 1.0},
- {1, 6, 363.444958, 150.838144, 1.0}, {2, 6, 876.374531, 114.916206, 1.0},
- };
+ {1, 0, 212.172775, 354.713538, 1.0},
+ {2, 0, 773.468399, 358.735306, 1.0},
+ {1, 1, 62.415197, 287.905354, 1.0},
+ {2, 1, 619.103336, 324.402537, 1.0},
+ {1, 2, 206.847939, 237.567925, 1.0},
+ {2, 2, 737.496986, 247.881383, 1.0},
+ {1, 3, 351.743889, 316.415906, 1.0},
+ {2, 3, 908.779621, 290.703617, 1.0},
+ {1, 4, 232.941413, 54.265443, 1.0},
+ {2, 4, 719.444847, 63.062531, 1.0},
+ {1, 5, 96.391611, 119.283537, 1.0},
+ {2, 5, 611.413136, 160.890715, 1.0},
+ {1, 6, 363.444958, 150.838144, 1.0},
+ {2, 6, 876.374531, 114.916206, 1.0},
+ };
int num_markers = sizeof(markers) / sizeof(Marker);
Tracks tracks;
@@ -65,12 +72,14 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) {
NULL);
Mat3 expected_rotation;
+ // clang-format off
expected_rotation << 0.98215101743472, 0.17798354937546, 0.06083777694542,
-0.16875283983360, 0.97665300495333, -0.13293376908719,
-0.08307742172243, 0.12029448893171, 0.98925597189636;
+ // clang-format on
- Mat3 &first_camera_R = reconstruction.CameraForImage(1)->R;
- Mat3 &second_camera_R = reconstruction.CameraForImage(2)->R;
+ Mat3& first_camera_R = reconstruction.CameraForImage(1)->R;
+ Mat3& second_camera_R = reconstruction.CameraForImage(2)->R;
EXPECT_TRUE(Mat3::Identity().isApprox(first_camera_R, kTolerance));
EXPECT_TRUE(expected_rotation.isApprox(second_camera_R, kTolerance));
diff --git a/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h b/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h
index cbea599fccd..79fa3ab8379 100644
--- a/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h
+++ b/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h
@@ -40,7 +40,7 @@ class PackedIntrinsics {
OFFSET_FOCAL_LENGTH,
OFFSET_PRINCIPAL_POINT_X,
OFFSET_PRINCIPAL_POINT_Y,
-
+
// Distortion model coefficients.
OFFSET_K1,
OFFSET_K2,
@@ -48,7 +48,7 @@ class PackedIntrinsics {
OFFSET_K4,
OFFSET_P1,
OFFSET_P2,
-
+
// Number of parameters which are to be stored in the block.
NUM_PARAMETERS,
};
@@ -66,12 +66,12 @@ class PackedIntrinsics {
// point.
#define DEFINE_PARAMETER(parameter_name) \
- void Set ## parameter_name(double value) { \
- SetParameter(OFFSET_ ## parameter_name, value); \
- } \
- double Get ## parameter_name() const { \
- return GetParameter(OFFSET_ ## parameter_name); \
+ void Set##parameter_name(double value) { \
+ SetParameter(OFFSET_##parameter_name, value); \
} \
+ double Get##parameter_name() const { \
+ return GetParameter(OFFSET_##parameter_name); \
+ }
DEFINE_PARAMETER(K1)
DEFINE_PARAMETER(K2)
@@ -94,11 +94,11 @@ class PackedIntrinsics {
// All intrinsics parameters packed into a single block.
// Use OFFSET_FOO indexes to access corresponding values.
- array<double, NUM_PARAMETERS> parameters_;
+ array<double, NUM_PARAMETERS> parameters_;
// Indexed by parameter offset, set to truth if the value of the parameter is
// explicitly specified.
- array<bool, NUM_PARAMETERS> known_parameters_;
+ array<bool, NUM_PARAMETERS> known_parameters_;
};
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.cc b/intern/libmv/libmv/simple_pipeline/pipeline.cc
index 728601f3732..5d52aeb7406 100644
--- a/intern/libmv/libmv/simple_pipeline/pipeline.cc
+++ b/intern/libmv/libmv/simple_pipeline/pipeline.cc
@@ -24,11 +24,11 @@
#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/bundle.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
#include "libmv/simple_pipeline/intersect.h"
-#include "libmv/simple_pipeline/resect.h"
#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/resect.h"
#include "libmv/simple_pipeline/tracks.h"
-#include "libmv/simple_pipeline/camera_intrinsics.h"
#ifdef _MSC_VER
# define snprintf _snprintf
@@ -46,24 +46,25 @@ struct EuclideanPipelineRoutines {
typedef EuclideanCamera Camera;
typedef EuclideanPoint Point;
- static void Bundle(const Tracks &tracks,
- EuclideanReconstruction *reconstruction) {
+ static void Bundle(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction) {
EuclideanBundle(tracks, reconstruction);
}
- static bool Resect(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction, bool final_pass) {
+ static bool Resect(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction,
+ bool final_pass) {
return EuclideanResect(markers, reconstruction, final_pass);
}
- static bool Intersect(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction) {
+ static bool Intersect(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction) {
return EuclideanIntersect(markers, reconstruction);
}
- static Marker ProjectMarker(const EuclideanPoint &point,
- const EuclideanCamera &camera,
- const CameraIntrinsics &intrinsics) {
+ static Marker ProjectMarker(const EuclideanPoint& point,
+ const EuclideanCamera& camera,
+ const CameraIntrinsics& intrinsics) {
Vec3 projected = camera.R * point.X + camera.t;
projected /= projected(2);
@@ -84,26 +85,27 @@ struct ProjectivePipelineRoutines {
typedef ProjectiveCamera Camera;
typedef ProjectivePoint Point;
- static void Bundle(const Tracks &tracks,
- ProjectiveReconstruction *reconstruction) {
+ static void Bundle(const Tracks& tracks,
+ ProjectiveReconstruction* reconstruction) {
ProjectiveBundle(tracks, reconstruction);
}
- static bool Resect(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction, bool final_pass) {
- (void) final_pass; // Ignored.
+ static bool Resect(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction,
+ bool final_pass) {
+ (void)final_pass; // Ignored.
return ProjectiveResect(markers, reconstruction);
}
- static bool Intersect(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction) {
+ static bool Intersect(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction) {
return ProjectiveIntersect(markers, reconstruction);
}
- static Marker ProjectMarker(const ProjectivePoint &point,
- const ProjectiveCamera &camera,
- const CameraIntrinsics &intrinsics) {
+ static Marker ProjectMarker(const ProjectivePoint& point,
+ const ProjectiveCamera& camera,
+ const CameraIntrinsics& intrinsics) {
Vec3 projected = camera.P * point.X;
projected /= projected(2);
@@ -122,28 +124,33 @@ struct ProjectivePipelineRoutines {
} // namespace
static void CompleteReconstructionLogProgress(
- ProgressUpdateCallback *update_callback,
+ ProgressUpdateCallback* update_callback,
double progress,
- const char *step = NULL) {
+ const char* step = NULL) {
if (update_callback) {
char message[256];
if (step)
- snprintf(message, sizeof(message), "Completing solution %d%% | %s",
- (int)(progress*100), step);
+ snprintf(message,
+ sizeof(message),
+ "Completing solution %d%% | %s",
+ (int)(progress * 100),
+ step);
else
- snprintf(message, sizeof(message), "Completing solution %d%%",
- (int)(progress*100));
+ snprintf(message,
+ sizeof(message),
+ "Completing solution %d%%",
+ (int)(progress * 100));
update_callback->invoke(progress, message);
}
}
-template<typename PipelineRoutines>
+template <typename PipelineRoutines>
void InternalCompleteReconstruction(
- const Tracks &tracks,
- typename PipelineRoutines::Reconstruction *reconstruction,
- ProgressUpdateCallback *update_callback = NULL) {
+ const Tracks& tracks,
+ typename PipelineRoutines::Reconstruction* reconstruction,
+ ProgressUpdateCallback* update_callback = NULL) {
int max_track = tracks.MaxTrack();
int max_image = tracks.MaxImage();
int num_resects = -1;
@@ -173,7 +180,7 @@ void InternalCompleteReconstruction(
<< " reconstructed markers for track " << track;
if (reconstructed_markers.size() >= 2) {
CompleteReconstructionLogProgress(update_callback,
- (double)tot_resects/(max_image));
+ (double)tot_resects / (max_image));
if (PipelineRoutines::Intersect(reconstructed_markers,
reconstruction)) {
num_intersects++;
@@ -184,9 +191,8 @@ void InternalCompleteReconstruction(
}
}
if (num_intersects) {
- CompleteReconstructionLogProgress(update_callback,
- (double)tot_resects/(max_image),
- "Bundling...");
+ CompleteReconstructionLogProgress(
+ update_callback, (double)tot_resects / (max_image), "Bundling...");
PipelineRoutines::Bundle(tracks, reconstruction);
LG << "Ran Bundle() after intersections.";
}
@@ -212,9 +218,9 @@ void InternalCompleteReconstruction(
<< " reconstructed markers for image " << image;
if (reconstructed_markers.size() >= 5) {
CompleteReconstructionLogProgress(update_callback,
- (double)tot_resects/(max_image));
- if (PipelineRoutines::Resect(reconstructed_markers,
- reconstruction, false)) {
+ (double)tot_resects / (max_image));
+ if (PipelineRoutines::Resect(
+ reconstructed_markers, reconstruction, false)) {
num_resects++;
tot_resects++;
LG << "Ran Resect() for image " << image;
@@ -224,9 +230,8 @@ void InternalCompleteReconstruction(
}
}
if (num_resects) {
- CompleteReconstructionLogProgress(update_callback,
- (double)tot_resects/(max_image),
- "Bundling...");
+ CompleteReconstructionLogProgress(
+ update_callback, (double)tot_resects / (max_image), "Bundling...");
PipelineRoutines::Bundle(tracks, reconstruction);
}
LG << "Did " << num_resects << " resects.";
@@ -249,9 +254,9 @@ void InternalCompleteReconstruction(
}
if (reconstructed_markers.size() >= 5) {
CompleteReconstructionLogProgress(update_callback,
- (double)tot_resects/(max_image));
- if (PipelineRoutines::Resect(reconstructed_markers,
- reconstruction, true)) {
+ (double)tot_resects / (max_image));
+ if (PipelineRoutines::Resect(
+ reconstructed_markers, reconstruction, true)) {
num_resects++;
LG << "Ran final Resect() for image " << image;
} else {
@@ -260,27 +265,26 @@ void InternalCompleteReconstruction(
}
}
if (num_resects) {
- CompleteReconstructionLogProgress(update_callback,
- (double)tot_resects/(max_image),
- "Bundling...");
+ CompleteReconstructionLogProgress(
+ update_callback, (double)tot_resects / (max_image), "Bundling...");
PipelineRoutines::Bundle(tracks, reconstruction);
}
}
-template<typename PipelineRoutines>
+template <typename PipelineRoutines>
double InternalReprojectionError(
- const Tracks &image_tracks,
- const typename PipelineRoutines::Reconstruction &reconstruction,
- const CameraIntrinsics &intrinsics) {
+ const Tracks& image_tracks,
+ const typename PipelineRoutines::Reconstruction& reconstruction,
+ const CameraIntrinsics& intrinsics) {
int num_skipped = 0;
int num_reprojected = 0;
double total_error = 0.0;
vector<Marker> markers = image_tracks.AllMarkers();
for (int i = 0; i < markers.size(); ++i) {
double weight = markers[i].weight;
- const typename PipelineRoutines::Camera *camera =
+ const typename PipelineRoutines::Camera* camera =
reconstruction.CameraForImage(markers[i].image);
- const typename PipelineRoutines::Point *point =
+ const typename PipelineRoutines::Point* point =
reconstruction.PointForTrack(markers[i].track);
if (!camera || !point || weight == 0.0) {
num_skipped++;
@@ -295,24 +299,25 @@ double InternalReprojectionError(
const int N = 100;
char line[N];
- snprintf(line, N,
- "image %-3d track %-3d "
- "x %7.1f y %7.1f "
- "rx %7.1f ry %7.1f "
- "ex %7.1f ey %7.1f"
- " e %7.1f",
- markers[i].image,
- markers[i].track,
- markers[i].x,
- markers[i].y,
- reprojected_marker.x,
- reprojected_marker.y,
- ex,
- ey,
- sqrt(ex*ex + ey*ey));
+ snprintf(line,
+ N,
+ "image %-3d track %-3d "
+ "x %7.1f y %7.1f "
+ "rx %7.1f ry %7.1f "
+ "ex %7.1f ey %7.1f"
+ " e %7.1f",
+ markers[i].image,
+ markers[i].track,
+ markers[i].x,
+ markers[i].y,
+ reprojected_marker.x,
+ reprojected_marker.y,
+ ex,
+ ey,
+ sqrt(ex * ex + ey * ey));
VLOG(1) << line;
- total_error += sqrt(ex*ex + ey*ey);
+ total_error += sqrt(ex * ex + ey * ey);
}
LG << "Skipped " << num_skipped << " markers.";
LG << "Reprojected " << num_reprojected << " markers.";
@@ -321,46 +326,41 @@ double InternalReprojectionError(
return total_error / num_reprojected;
}
-double EuclideanReprojectionError(const Tracks &image_tracks,
- const EuclideanReconstruction &reconstruction,
- const CameraIntrinsics &intrinsics) {
- return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
- reconstruction,
- intrinsics);
+double EuclideanReprojectionError(const Tracks& image_tracks,
+ const EuclideanReconstruction& reconstruction,
+ const CameraIntrinsics& intrinsics) {
+ return InternalReprojectionError<EuclideanPipelineRoutines>(
+ image_tracks, reconstruction, intrinsics);
}
double ProjectiveReprojectionError(
- const Tracks &image_tracks,
- const ProjectiveReconstruction &reconstruction,
- const CameraIntrinsics &intrinsics) {
- return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
- reconstruction,
- intrinsics);
+ const Tracks& image_tracks,
+ const ProjectiveReconstruction& reconstruction,
+ const CameraIntrinsics& intrinsics) {
+ return InternalReprojectionError<ProjectivePipelineRoutines>(
+ image_tracks, reconstruction, intrinsics);
}
-void EuclideanCompleteReconstruction(const Tracks &tracks,
- EuclideanReconstruction *reconstruction,
- ProgressUpdateCallback *update_callback) {
- InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
- reconstruction,
- update_callback);
+void EuclideanCompleteReconstruction(const Tracks& tracks,
+ EuclideanReconstruction* reconstruction,
+ ProgressUpdateCallback* update_callback) {
+ InternalCompleteReconstruction<EuclideanPipelineRoutines>(
+ tracks, reconstruction, update_callback);
}
-void ProjectiveCompleteReconstruction(const Tracks &tracks,
- ProjectiveReconstruction *reconstruction) {
+void ProjectiveCompleteReconstruction(
+ const Tracks& tracks, ProjectiveReconstruction* reconstruction) {
InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks,
reconstruction);
}
-void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
- const CameraIntrinsics &camera_intrinsics,
- Tracks *calibrated_tracks) {
+void InvertIntrinsicsForTracks(const Tracks& raw_tracks,
+ const CameraIntrinsics& camera_intrinsics,
+ Tracks* calibrated_tracks) {
vector<Marker> markers = raw_tracks.AllMarkers();
for (int i = 0; i < markers.size(); ++i) {
- camera_intrinsics.InvertIntrinsics(markers[i].x,
- markers[i].y,
- &(markers[i].x),
- &(markers[i].y));
+ camera_intrinsics.InvertIntrinsics(
+ markers[i].x, markers[i].y, &(markers[i].x), &(markers[i].y));
}
*calibrated_tracks = Tracks(markers);
}
diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.h b/intern/libmv/libmv/simple_pipeline/pipeline.h
index 4d1bd00c51f..d6b43536d46 100644
--- a/intern/libmv/libmv/simple_pipeline/pipeline.h
+++ b/intern/libmv/libmv/simple_pipeline/pipeline.h
@@ -22,8 +22,8 @@
#define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
#include "libmv/simple_pipeline/callbacks.h"
-#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
@@ -47,9 +47,9 @@ namespace libmv {
\sa EuclideanResect, EuclideanIntersect, EuclideanBundle
*/
void EuclideanCompleteReconstruction(
- const Tracks &tracks,
- EuclideanReconstruction *reconstruction,
- ProgressUpdateCallback *update_callback = NULL);
+ const Tracks& tracks,
+ EuclideanReconstruction* reconstruction,
+ ProgressUpdateCallback* update_callback = NULL);
/*!
Estimate camera matrices and homogeneous 3D coordinates for all frames and
@@ -71,27 +71,26 @@ void EuclideanCompleteReconstruction(
\sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle
*/
-void ProjectiveCompleteReconstruction(const Tracks &tracks,
- ProjectiveReconstruction *reconstruction);
-
+void ProjectiveCompleteReconstruction(const Tracks& tracks,
+ ProjectiveReconstruction* reconstruction);
class CameraIntrinsics;
// TODO(keir): Decide if we want these in the public API, and if so, what the
// appropriate include file is.
-double EuclideanReprojectionError(const Tracks &image_tracks,
- const EuclideanReconstruction &reconstruction,
- const CameraIntrinsics &intrinsics);
+double EuclideanReprojectionError(const Tracks& image_tracks,
+ const EuclideanReconstruction& reconstruction,
+ const CameraIntrinsics& intrinsics);
double ProjectiveReprojectionError(
- const Tracks &image_tracks,
- const ProjectiveReconstruction &reconstruction,
- const CameraIntrinsics &intrinsics);
+ const Tracks& image_tracks,
+ const ProjectiveReconstruction& reconstruction,
+ const CameraIntrinsics& intrinsics);
-void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
- const CameraIntrinsics &camera_intrinsics,
- Tracks *calibrated_tracks);
+void InvertIntrinsicsForTracks(const Tracks& raw_tracks,
+ const CameraIntrinsics& camera_intrinsics,
+ Tracks* calibrated_tracks);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction.cc b/intern/libmv/libmv/simple_pipeline/reconstruction.cc
index 851eedb5bb1..584f7440caf 100644
--- a/intern/libmv/libmv/simple_pipeline/reconstruction.cc
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction.cc
@@ -19,20 +19,21 @@
// IN THE SOFTWARE.
#include "libmv/simple_pipeline/reconstruction.h"
-#include "libmv/numeric/numeric.h"
#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
-EuclideanReconstruction::EuclideanReconstruction() {}
+EuclideanReconstruction::EuclideanReconstruction() {
+}
EuclideanReconstruction::EuclideanReconstruction(
- const EuclideanReconstruction &other) {
+ const EuclideanReconstruction& other) {
image_to_cameras_map_ = other.image_to_cameras_map_;
points_ = other.points_;
}
-EuclideanReconstruction &EuclideanReconstruction::operator=(
- const EuclideanReconstruction &other) {
+EuclideanReconstruction& EuclideanReconstruction::operator=(
+ const EuclideanReconstruction& other) {
if (&other != this) {
image_to_cameras_map_ = other.image_to_cameras_map_;
points_ = other.points_;
@@ -41,9 +42,9 @@ EuclideanReconstruction &EuclideanReconstruction::operator=(
}
void EuclideanReconstruction::InsertCamera(int image,
- const Mat3 &R,
- const Vec3 &t) {
- LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t;
+ const Mat3& R,
+ const Vec3& t) {
+ LG << "InsertCamera " << image << ":\nR:\n" << R << "\nt:\n" << t;
EuclideanCamera camera;
camera.image = image;
@@ -53,7 +54,7 @@ void EuclideanReconstruction::InsertCamera(int image,
image_to_cameras_map_.insert(make_pair(image, camera));
}
-void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
+void EuclideanReconstruction::InsertPoint(int track, const Vec3& X) {
LG << "InsertPoint " << track << ":\n" << X;
if (track >= points_.size()) {
points_.resize(track + 1);
@@ -62,13 +63,12 @@ void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
points_[track].X = X;
}
-EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) {
- return const_cast<EuclideanCamera *>(
- static_cast<const EuclideanReconstruction *>(
- this)->CameraForImage(image));
+EuclideanCamera* EuclideanReconstruction::CameraForImage(int image) {
+ return const_cast<EuclideanCamera*>(
+ static_cast<const EuclideanReconstruction*>(this)->CameraForImage(image));
}
-const EuclideanCamera *EuclideanReconstruction::CameraForImage(
+const EuclideanCamera* EuclideanReconstruction::CameraForImage(
int image) const {
ImageToCameraMap::const_iterator it = image_to_cameras_map_.find(image);
if (it == image_to_cameras_map_.end()) {
@@ -86,16 +86,16 @@ vector<EuclideanCamera> EuclideanReconstruction::AllCameras() const {
return cameras;
}
-EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) {
- return const_cast<EuclideanPoint *>(
- static_cast<const EuclideanReconstruction *>(this)->PointForTrack(track));
+EuclideanPoint* EuclideanReconstruction::PointForTrack(int track) {
+ return const_cast<EuclideanPoint*>(
+ static_cast<const EuclideanReconstruction*>(this)->PointForTrack(track));
}
-const EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) const {
+const EuclideanPoint* EuclideanReconstruction::PointForTrack(int track) const {
if (track < 0 || track >= points_.size()) {
return NULL;
}
- const EuclideanPoint *point = &points_[track];
+ const EuclideanPoint* point = &points_[track];
if (point->track == -1) {
return NULL;
}
@@ -112,8 +112,8 @@ vector<EuclideanPoint> EuclideanReconstruction::AllPoints() const {
return points;
}
-void ProjectiveReconstruction::InsertCamera(int image, const Mat34 &P) {
- LG << "InsertCamera " << image << ":\nP:\n"<< P;
+void ProjectiveReconstruction::InsertCamera(int image, const Mat34& P) {
+ LG << "InsertCamera " << image << ":\nP:\n" << P;
ProjectiveCamera camera;
camera.image = image;
@@ -122,7 +122,7 @@ void ProjectiveReconstruction::InsertCamera(int image, const Mat34 &P) {
image_to_cameras_map_.insert(make_pair(image, camera));
}
-void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
+void ProjectiveReconstruction::InsertPoint(int track, const Vec4& X) {
LG << "InsertPoint " << track << ":\n" << X;
if (track >= points_.size()) {
points_.resize(track + 1);
@@ -131,17 +131,17 @@ void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
points_[track].X = X;
}
-ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) {
- return const_cast<ProjectiveCamera *>(
- static_cast<const ProjectiveReconstruction *>(
- this)->CameraForImage(image));
+ProjectiveCamera* ProjectiveReconstruction::CameraForImage(int image) {
+ return const_cast<ProjectiveCamera*>(
+ static_cast<const ProjectiveReconstruction*>(this)->CameraForImage(
+ image));
}
-const ProjectiveCamera *ProjectiveReconstruction::CameraForImage(
+const ProjectiveCamera* ProjectiveReconstruction::CameraForImage(
int image) const {
ImageToCameraMap::const_iterator it = image_to_cameras_map_.find(image);
if (it == image_to_cameras_map_.end()) {
- return NULL;
+ return NULL;
}
return &it->second;
}
@@ -155,16 +155,17 @@ vector<ProjectiveCamera> ProjectiveReconstruction::AllCameras() const {
return cameras;
}
-ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) {
- return const_cast<ProjectivePoint *>(
- static_cast<const ProjectiveReconstruction *>(this)->PointForTrack(track));
+ProjectivePoint* ProjectiveReconstruction::PointForTrack(int track) {
+ return const_cast<ProjectivePoint*>(
+ static_cast<const ProjectiveReconstruction*>(this)->PointForTrack(track));
}
-const ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) const {
+const ProjectivePoint* ProjectiveReconstruction::PointForTrack(
+ int track) const {
if (track < 0 || track >= points_.size()) {
return NULL;
}
- const ProjectivePoint *point = &points_[track];
+ const ProjectivePoint* point = &points_[track];
if (point->track == -1) {
return NULL;
}
diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction.h b/intern/libmv/libmv/simple_pipeline/reconstruction.h
index 544aeac042e..56b2ba34c91 100644
--- a/intern/libmv/libmv/simple_pipeline/reconstruction.h
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction.h
@@ -21,14 +21,15 @@
#ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
-#include "libmv/base/vector.h"
#include "libmv/base/map.h"
+#include "libmv/base/vector.h"
#include "libmv/numeric/numeric.h"
namespace libmv {
/*!
- A EuclideanCamera is the location and rotation of the camera viewing \a image.
+ A EuclideanCamera is the location and rotation of the camera viewing \a
+ image.
\a image identify which image from \link Tracks this camera represents.
\a R is a 3x3 matrix representing the rotation of the camera.
@@ -38,7 +39,7 @@ namespace libmv {
*/
struct EuclideanCamera {
EuclideanCamera() : image(-1) {}
- EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {}
+ EuclideanCamera(const EuclideanCamera& c) : image(c.image), R(c.R), t(c.t) {}
int image;
Mat3 R;
@@ -55,7 +56,7 @@ struct EuclideanCamera {
*/
struct EuclideanPoint {
EuclideanPoint() : track(-1) {}
- EuclideanPoint(const EuclideanPoint &p) : track(p.track), X(p.X) {}
+ EuclideanPoint(const EuclideanPoint& p) : track(p.track), X(p.X) {}
int track;
Vec3 X;
};
@@ -78,9 +79,9 @@ class EuclideanReconstruction {
EuclideanReconstruction();
/// Copy constructor.
- EuclideanReconstruction(const EuclideanReconstruction &other);
+ EuclideanReconstruction(const EuclideanReconstruction& other);
- EuclideanReconstruction &operator=(const EuclideanReconstruction &other);
+ EuclideanReconstruction& operator=(const EuclideanReconstruction& other);
/*!
Insert a camera into the set. If there is already a camera for the given
@@ -92,7 +93,7 @@ class EuclideanReconstruction {
\note You should use the same \a image identifier as in \link Tracks.
*/
- void InsertCamera(int image, const Mat3 &R, const Vec3 &t);
+ void InsertCamera(int image, const Mat3& R, const Vec3& t);
/*!
Insert a point into the reconstruction. If there is already a point for
@@ -104,18 +105,18 @@ class EuclideanReconstruction {
\note You should use the same \a track identifier as in \link Tracks.
*/
- void InsertPoint(int track, const Vec3 &X);
+ void InsertPoint(int track, const Vec3& X);
/// Returns a pointer to the camera corresponding to \a image.
- EuclideanCamera *CameraForImage(int image);
- const EuclideanCamera *CameraForImage(int image) const;
+ EuclideanCamera* CameraForImage(int image);
+ const EuclideanCamera* CameraForImage(int image) const;
/// Returns all cameras.
vector<EuclideanCamera> AllCameras() const;
/// Returns a pointer to the point corresponding to \a track.
- EuclideanPoint *PointForTrack(int track);
- const EuclideanPoint *PointForTrack(int track) const;
+ EuclideanPoint* PointForTrack(int track);
+ const EuclideanPoint* PointForTrack(int track) const;
/// Returns all points.
vector<EuclideanPoint> AllPoints() const;
@@ -139,7 +140,7 @@ class EuclideanReconstruction {
*/
struct ProjectiveCamera {
ProjectiveCamera() : image(-1) {}
- ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {}
+ ProjectiveCamera(const ProjectiveCamera& c) : image(c.image), P(c.P) {}
int image;
Mat34 P;
@@ -155,7 +156,7 @@ struct ProjectiveCamera {
*/
struct ProjectivePoint {
ProjectivePoint() : track(-1) {}
- ProjectivePoint(const ProjectivePoint &p) : track(p.track), X(p.X) {}
+ ProjectivePoint(const ProjectivePoint& p) : track(p.track), X(p.X) {}
int track;
Vec4 X;
};
@@ -184,7 +185,7 @@ class ProjectiveReconstruction {
\note You should use the same \a image identifier as in \link Tracks.
*/
- void InsertCamera(int image, const Mat34 &P);
+ void InsertCamera(int image, const Mat34& P);
/*!
Insert a point into the reconstruction. If there is already a point for
@@ -196,18 +197,18 @@ class ProjectiveReconstruction {
\note You should use the same \a track identifier as in \link Tracks.
*/
- void InsertPoint(int track, const Vec4 &X);
+ void InsertPoint(int track, const Vec4& X);
/// Returns a pointer to the camera corresponding to \a image.
- ProjectiveCamera *CameraForImage(int image);
- const ProjectiveCamera *CameraForImage(int image) const;
+ ProjectiveCamera* CameraForImage(int image);
+ const ProjectiveCamera* CameraForImage(int image) const;
/// Returns all cameras.
vector<ProjectiveCamera> AllCameras() const;
/// Returns a pointer to the point corresponding to \a track.
- ProjectivePoint *PointForTrack(int track);
- const ProjectivePoint *PointForTrack(int track) const;
+ ProjectivePoint* PointForTrack(int track);
+ const ProjectivePoint* PointForTrack(int track) const;
/// Returns all points.
vector<ProjectivePoint> AllPoints() const;
diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
index 40ac23be7a2..04fbb536d31 100644
--- a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
@@ -23,7 +23,7 @@
namespace libmv {
-void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) {
+void EuclideanScaleToUnity(EuclideanReconstruction* reconstruction) {
vector<EuclideanCamera> all_cameras = reconstruction->AllCameras();
vector<EuclideanPoint> all_points = reconstruction->AllPoints();
@@ -53,14 +53,14 @@ void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) {
// Rescale cameras positions.
for (int i = 0; i < all_cameras.size(); ++i) {
int image = all_cameras[i].image;
- EuclideanCamera *camera = reconstruction->CameraForImage(image);
+ EuclideanCamera* camera = reconstruction->CameraForImage(image);
camera->t = camera->t * scale_factor;
}
// Rescale points positions.
for (int i = 0; i < all_points.size(); ++i) {
int track = all_points[i].track;
- EuclideanPoint *point = reconstruction->PointForTrack(track);
+ EuclideanPoint* point = reconstruction->PointForTrack(track);
point->X = point->X * scale_factor;
}
}
diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h
index f2349ff5146..c164878ee25 100644
--- a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h
@@ -29,7 +29,7 @@ namespace libmv {
Scale euclidean reconstruction in a way variance of
camera centers equals to one.
*/
-void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction);
+void EuclideanScaleToUnity(EuclideanReconstruction* reconstruction);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/resect.cc b/intern/libmv/libmv/simple_pipeline/resect.cc
index e73fc44df2a..b5736767edd 100644
--- a/intern/libmv/libmv/simple_pipeline/resect.cc
+++ b/intern/libmv/libmv/simple_pipeline/resect.cc
@@ -25,17 +25,17 @@
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/euclidean_resection.h"
-#include "libmv/multiview/resection.h"
#include "libmv/multiview/projection.h"
-#include "libmv/numeric/numeric.h"
+#include "libmv/multiview/resection.h"
#include "libmv/numeric/levenberg_marquardt.h"
+#include "libmv/numeric/numeric.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
namespace {
-Mat2X PointMatrixFromMarkers(const vector<Marker> &markers) {
+Mat2X PointMatrixFromMarkers(const vector<Marker>& markers) {
Mat2X points(2, markers.size());
for (int i = 0; i < markers.size(); ++i) {
points(0, i) = markers[i].x;
@@ -53,19 +53,19 @@ Mat2X PointMatrixFromMarkers(const vector<Marker> &markers) {
// axis to rotate around and the magnitude is the amount of the rotation.
struct EuclideanResectCostFunction {
public:
- typedef Vec FMatrixType;
+ typedef Vec FMatrixType;
typedef Vec6 XMatrixType;
- EuclideanResectCostFunction(const vector<Marker> &markers,
- const EuclideanReconstruction &reconstruction,
- const Mat3 &initial_R)
- : markers(markers),
- reconstruction(reconstruction),
- initial_R(initial_R) {}
+ EuclideanResectCostFunction(const vector<Marker>& markers,
+ const EuclideanReconstruction& reconstruction,
+ const Mat3& initial_R)
+ : markers(markers),
+ reconstruction(reconstruction),
+ initial_R(initial_R) {}
// dRt has dR (delta R) encoded as a euler vector in the first 3 parameters,
// followed by t in the next 3 parameters.
- Vec operator()(const Vec6 &dRt) const {
+ Vec operator()(const Vec6& dRt) const {
// Unpack R, t from dRt.
Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R;
Vec3 t = dRt.tail<3>();
@@ -74,25 +74,26 @@ struct EuclideanResectCostFunction {
Vec residuals(2 * markers.size());
residuals.setZero();
for (int i = 0; i < markers.size(); ++i) {
- const EuclideanPoint &point =
+ const EuclideanPoint& point =
*reconstruction.PointForTrack(markers[i].track);
Vec3 projected = R * point.X + t;
projected /= projected(2);
- residuals[2*i + 0] = projected(0) - markers[i].x;
- residuals[2*i + 1] = projected(1) - markers[i].y;
+ residuals[2 * i + 0] = projected(0) - markers[i].x;
+ residuals[2 * i + 1] = projected(1) - markers[i].y;
}
return residuals;
}
- const vector<Marker> &markers;
- const EuclideanReconstruction &reconstruction;
- const Mat3 &initial_R;
+ const vector<Marker>& markers;
+ const EuclideanReconstruction& reconstruction;
+ const Mat3& initial_R;
};
} // namespace
-bool EuclideanResect(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction, bool final_pass) {
+bool EuclideanResect(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction,
+ bool final_pass) {
if (markers.size() < 5) {
return false;
}
@@ -106,9 +107,9 @@ bool EuclideanResect(const vector<Marker> &markers,
Mat3 R;
Vec3 t;
- if (0 || !euclidean_resection::EuclideanResection(
- points_2d, points_3d, &R, &t,
- euclidean_resection::RESECTION_EPNP)) {
+ if (0 ||
+ !euclidean_resection::EuclideanResection(
+ points_2d, points_3d, &R, &t, euclidean_resection::RESECTION_EPNP)) {
// printf("Resection for image %d failed\n", markers[0].image);
LG << "Resection for image " << markers[0].image << " failed;"
<< " trying fallback projective resection.";
@@ -116,7 +117,8 @@ bool EuclideanResect(const vector<Marker> &markers,
LG << "No fallback; failing resection for " << markers[0].image;
return false;
- if (!final_pass) return false;
+ if (!final_pass)
+ return false;
// Euclidean resection failed. Fall back to projective resection, which is
// less reliable but better conditioned when there are many points.
Mat34 P;
@@ -173,7 +175,9 @@ bool EuclideanResect(const vector<Marker> &markers,
t = dRt.tail<3>();
LG << "Resection for image " << markers[0].image << " got:\n"
- << "R:\n" << R << "\nt:\n" << t;
+ << "R:\n"
+ << R << "\nt:\n"
+ << t;
reconstruction->InsertCamera(markers[0].image, R, t);
return true;
}
@@ -186,15 +190,14 @@ namespace {
// freedom drift.
struct ProjectiveResectCostFunction {
public:
- typedef Vec FMatrixType;
+ typedef Vec FMatrixType;
typedef Vec12 XMatrixType;
- ProjectiveResectCostFunction(const vector<Marker> &markers,
- const ProjectiveReconstruction &reconstruction)
- : markers(markers),
- reconstruction(reconstruction) {}
+ ProjectiveResectCostFunction(const vector<Marker>& markers,
+ const ProjectiveReconstruction& reconstruction)
+ : markers(markers), reconstruction(reconstruction) {}
- Vec operator()(const Vec12 &vector_P) const {
+ Vec operator()(const Vec12& vector_P) const {
// Unpack P from vector_P.
Map<const Mat34> P(vector_P.data(), 3, 4);
@@ -202,24 +205,24 @@ struct ProjectiveResectCostFunction {
Vec residuals(2 * markers.size());
residuals.setZero();
for (int i = 0; i < markers.size(); ++i) {
- const ProjectivePoint &point =
+ const ProjectivePoint& point =
*reconstruction.PointForTrack(markers[i].track);
Vec3 projected = P * point.X;
projected /= projected(2);
- residuals[2*i + 0] = projected(0) - markers[i].x;
- residuals[2*i + 1] = projected(1) - markers[i].y;
+ residuals[2 * i + 0] = projected(0) - markers[i].x;
+ residuals[2 * i + 1] = projected(1) - markers[i].y;
}
return residuals;
}
- const vector<Marker> &markers;
- const ProjectiveReconstruction &reconstruction;
+ const vector<Marker>& markers;
+ const ProjectiveReconstruction& reconstruction;
};
} // namespace
-bool ProjectiveResect(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction) {
+bool ProjectiveResect(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction) {
if (markers.size() < 5) {
return false;
}
@@ -263,7 +266,8 @@ bool ProjectiveResect(const vector<Marker> &markers,
P = Map<Mat34>(vector_P.data(), 3, 4);
LG << "Resection for image " << markers[0].image << " got:\n"
- << "P:\n" << P;
+ << "P:\n"
+ << P;
reconstruction->InsertCamera(markers[0].image, P);
return true;
}
diff --git a/intern/libmv/libmv/simple_pipeline/resect.h b/intern/libmv/libmv/simple_pipeline/resect.h
index f13d2e2d425..13c3d66bd37 100644
--- a/intern/libmv/libmv/simple_pipeline/resect.h
+++ b/intern/libmv/libmv/simple_pipeline/resect.h
@@ -22,8 +22,8 @@
#define LIBMV_SIMPLE_PIPELINE_RESECT_H
#include "libmv/base/vector.h"
-#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
namespace libmv {
@@ -51,8 +51,9 @@ namespace libmv {
\sa EuclideanIntersect, EuclideanReconstructTwoFrames
*/
-bool EuclideanResect(const vector<Marker> &markers,
- EuclideanReconstruction *reconstruction, bool final_pass);
+bool EuclideanResect(const vector<Marker>& markers,
+ EuclideanReconstruction* reconstruction,
+ bool final_pass);
/*!
Estimate the projective pose of a camera from 2D to 3D correspondences.
@@ -78,8 +79,8 @@ bool EuclideanResect(const vector<Marker> &markers,
\sa ProjectiveIntersect, ProjectiveReconstructTwoFrames
*/
-bool ProjectiveResect(const vector<Marker> &markers,
- ProjectiveReconstruction *reconstruction);
+bool ProjectiveResect(const vector<Marker>& markers,
+ ProjectiveReconstruction* reconstruction);
} // namespace libmv
diff --git a/intern/libmv/libmv/simple_pipeline/resect_test.cc b/intern/libmv/libmv/simple_pipeline/resect_test.cc
index 811edd282d8..ecf3f9b673d 100644
--- a/intern/libmv/libmv/simple_pipeline/resect_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/resect_test.cc
@@ -153,7 +153,7 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
// not precise enough with only 4 points.
//
// TODO(jmichot): Reenable this test when there is nonlinear refinement.
-#if 0
+# if 0
R_output.setIdentity();
T_output.setZero();
@@ -163,7 +163,7 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/
-#endif
+# endif
}
// TODO(jmichot): Reduce the code duplication here with the code above.
diff --git a/intern/libmv/libmv/simple_pipeline/tracks.cc b/intern/libmv/libmv/simple_pipeline/tracks.cc
index d5d009708ba..66243807a4b 100644
--- a/intern/libmv/libmv/simple_pipeline/tracks.cc
+++ b/intern/libmv/libmv/simple_pipeline/tracks.cc
@@ -21,31 +21,31 @@
#include "libmv/simple_pipeline/tracks.h"
#include <algorithm>
-#include <vector>
#include <iterator>
+#include <vector>
#include "libmv/numeric/numeric.h"
namespace libmv {
-Tracks::Tracks(const Tracks &other) {
+Tracks::Tracks(const Tracks& other) {
markers_ = other.markers_;
}
-Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {}
+Tracks::Tracks(const vector<Marker>& markers) : markers_(markers) {
+}
void Tracks::Insert(int image, int track, double x, double y, double weight) {
// TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
// adding a smarter data structure like a set<>.
for (int i = 0; i < markers_.size(); ++i) {
- if (markers_[i].image == image &&
- markers_[i].track == track) {
+ if (markers_[i].image == image && markers_[i].track == track) {
markers_[i].x = x;
markers_[i].y = y;
return;
}
}
- Marker marker = { image, track, x, y, weight };
+ Marker marker = {image, track, x, y, weight};
markers_.push_back(marker);
}
@@ -101,15 +101,17 @@ vector<Marker> Tracks::MarkersForTracksInBothImages(int image1,
std::sort(image2_tracks.begin(), image2_tracks.end());
std::vector<int> intersection;
- std::set_intersection(image1_tracks.begin(), image1_tracks.end(),
- image2_tracks.begin(), image2_tracks.end(),
+ std::set_intersection(image1_tracks.begin(),
+ image1_tracks.end(),
+ image2_tracks.begin(),
+ image2_tracks.end(),
std::back_inserter(intersection));
vector<Marker> markers;
for (int i = 0; i < markers_.size(); ++i) {
if ((markers_[i].image == image1 || markers_[i].image == image2) &&
- std::binary_search(intersection.begin(), intersection.end(),
- markers_[i].track)) {
+ std::binary_search(
+ intersection.begin(), intersection.end(), markers_[i].track)) {
markers.push_back(markers_[i]);
}
}
@@ -122,7 +124,7 @@ Marker Tracks::MarkerInImageForTrack(int image, int track) const {
return markers_[i];
}
}
- Marker null = { -1, -1, -1, -1, 0.0 };
+ Marker null = {-1, -1, -1, -1, 0.0};
return null;
}
@@ -168,12 +170,12 @@ int Tracks::NumMarkers() const {
return markers_.size();
}
-void CoordinatesForMarkersInImage(const vector<Marker> &markers,
+void CoordinatesForMarkersInImage(const vector<Marker>& markers,
int image,
- Mat *coordinates) {
+ Mat* coordinates) {
vector<Vec2> coords;
for (int i = 0; i < markers.size(); ++i) {
- const Marker &marker = markers[i];
+ const Marker& marker = markers[i];
if (markers[i].image == image) {
coords.push_back(Vec2(marker.x, marker.y));
}
diff --git a/intern/libmv/libmv/simple_pipeline/tracks.h b/intern/libmv/libmv/simple_pipeline/tracks.h
index 752d2790a1c..c3df3a223d8 100644
--- a/intern/libmv/libmv/simple_pipeline/tracks.h
+++ b/intern/libmv/libmv/simple_pipeline/tracks.h
@@ -36,7 +36,8 @@ namespace libmv {
\a weight is used by bundle adjustment and weight means how much the
track affects on a final solution.
- \note Markers are typically aggregated with the help of the \link Tracks class.
+ \note Markers are typically aggregated with the help of the \link Tracks
+ class.
\sa Tracks
*/
@@ -56,19 +57,20 @@ struct Marker {
images, which must get created before any 3D reconstruction can take place.
The container has several fast lookups for queries typically needed for
- structure from motion algorithms, such as \link MarkersForTracksInBothImages().
+ structure from motion algorithms, such as \link
+ MarkersForTracksInBothImages().
\sa Marker
*/
class Tracks {
public:
- Tracks() { }
+ Tracks() {}
// Copy constructor for a tracks object.
- Tracks(const Tracks &other);
+ Tracks(const Tracks& other);
/// Construct a new tracks object using the given markers to start.
- explicit Tracks(const vector<Marker> &markers);
+ explicit Tracks(const vector<Marker>& markers);
/*!
Inserts a marker into the set. If there is already a marker for the given
@@ -129,9 +131,9 @@ class Tracks {
vector<Marker> markers_;
};
-void CoordinatesForMarkersInImage(const vector<Marker> &markers,
+void CoordinatesForMarkersInImage(const vector<Marker>& markers,
int image,
- Mat *coordinates);
+ Mat* coordinates);
} // namespace libmv
diff --git a/intern/libmv/libmv/threading/threading.h b/intern/libmv/libmv/threading/threading.h
index f23bf6f172c..da625e02424 100644
--- a/intern/libmv/libmv/threading/threading.h
+++ b/intern/libmv/libmv/threading/threading.h
@@ -31,7 +31,7 @@
namespace libmv {
#if COMPILER_SUPPORTS_CXX11
-using mutex = std::mutex;
+using mutex = std::mutex;
using scoped_lock = std::unique_lock<std::mutex>;
using condition_variable = std::condition_variable;
#else
diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.cc b/intern/libmv/libmv/tracking/brute_region_tracker.cc
index 85aecb7f633..7007fb9440b 100644
--- a/intern/libmv/libmv/tracking/brute_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/brute_region_tracker.cc
@@ -25,31 +25,30 @@
#endif
#include "libmv/base/aligned_malloc.h"
-#include "libmv/image/image.h"
#include "libmv/image/convolve.h"
#include "libmv/image/correlation.h"
+#include "libmv/image/image.h"
#include "libmv/image/sample.h"
#include "libmv/logging/logging.h"
namespace libmv {
namespace {
-bool RegionIsInBounds(const FloatImage &image1,
- double x, double y,
+bool RegionIsInBounds(const FloatImage& image1,
+ double x,
+ double y,
int half_window_size) {
// Check the minimum coordinates.
int min_x = floor(x) - half_window_size - 1;
int min_y = floor(y) - half_window_size - 1;
- if (min_x < 0.0 ||
- min_y < 0.0) {
+ if (min_x < 0.0 || min_y < 0.0) {
return false;
}
// Check the maximum coordinates.
int max_x = ceil(x) + half_window_size + 1;
int max_y = ceil(y) + half_window_size + 1;
- if (max_x > image1.cols() ||
- max_y > image1.rows()) {
+ if (max_x > image1.cols() || max_y > image1.rows()) {
return false;
}
@@ -69,14 +68,15 @@ bool RegionIsInBounds(const FloatImage &image1,
// and "b", since the SSE load instructionst will pull in memory past the end
// of the arrays if their size is not a multiple of 16.
inline static __m128i SumOfAbsoluteDifferencesContiguousSSE(
- const unsigned char *a, // aligned
- const unsigned char *b, // not aligned
+ const unsigned char* a, // aligned
+ const unsigned char* b, // not aligned
unsigned int size,
__m128i sad) {
// Do the bulk of the work as 16-way integer operations.
for (unsigned int j = 0; j < size / 16; j++) {
- sad = _mm_add_epi32(sad, _mm_sad_epu8( _mm_load_si128 ((__m128i*)(a + 16 * j)),
- _mm_loadu_si128((__m128i*)(b + 16 * j))));
+ sad = _mm_add_epi32(sad,
+ _mm_sad_epu8(_mm_load_si128((__m128i*)(a + 16 * j)),
+ _mm_loadu_si128((__m128i*)(b + 16 * j))));
}
// Handle the trailing end.
// TODO(keir): Benchmark to verify that the below SSE is a win compared to a
@@ -90,32 +90,63 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE(
unsigned int remainder = size % 16u;
if (remainder) {
unsigned int j = size / 16;
- __m128i a_trail = _mm_load_si128 ((__m128i*)(a + 16 * j));
+ __m128i a_trail = _mm_load_si128((__m128i*)(a + 16 * j));
__m128i b_trail = _mm_loadu_si128((__m128i*)(b + 16 * j));
__m128i mask;
switch (remainder) {
-#define X 0xff
- case 1: mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 2: mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 3: mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 4: mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 5: mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 6: mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 7: mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 8: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0); break;
- case 9: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0); break;
- case 10: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0); break;
- case 11: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0); break;
- case 12: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0); break;
- case 13: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); break;
- case 14: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); break;
- case 15: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); break;
+# define X 0xff
+ case 1:
+ mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 2:
+ mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 3:
+ mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 4:
+ mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 5:
+ mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 6:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 7:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 8:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 9:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case 10:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0);
+ break;
+ case 11:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0);
+ break;
+ case 12:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0);
+ break;
+ case 13:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0);
+ break;
+ case 14:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0);
+ break;
+ case 15:
+ mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0);
+ break;
// To silence compiler warning.
default: mask = _mm_setzero_si128(); break;
-#undef X
+# undef X
}
- sad = _mm_add_epi32(sad, _mm_sad_epu8(_mm_and_si128(mask, a_trail),
- _mm_and_si128(mask, b_trail)));
+ sad = _mm_add_epi32(sad,
+ _mm_sad_epu8(_mm_and_si128(mask, a_trail),
+ _mm_and_si128(mask, b_trail)));
}
return sad;
}
@@ -124,13 +155,12 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE(
// Computes the sum of absolute differences between pattern and image. Pattern
// must be 16-byte aligned, and the stride must be a multiple of 16. The image
// does pointer does not have to be aligned.
-int SumOfAbsoluteDifferencesContiguousImage(
- const unsigned char *pattern,
- unsigned int pattern_width,
- unsigned int pattern_height,
- unsigned int pattern_stride,
- const unsigned char *image,
- unsigned int image_stride) {
+int SumOfAbsoluteDifferencesContiguousImage(const unsigned char* pattern,
+ unsigned int pattern_width,
+ unsigned int pattern_height,
+ unsigned int pattern_stride,
+ const unsigned char* image,
+ unsigned int image_stride) {
#ifdef __SSE2__
// TODO(keir): Add interleaved accumulation, where accumulation is done into
// two or more SSE registers that then get combined at the end. This reduces
@@ -145,8 +175,7 @@ int SumOfAbsoluteDifferencesContiguousImage(
sad);
}
return _mm_cvtsi128_si32(
- _mm_add_epi32(sad,
- _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2))));
+ _mm_add_epi32(sad, _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2))));
#else
int sad = 0;
for (int r = 0; r < pattern_height; ++r) {
@@ -161,12 +190,13 @@ int SumOfAbsoluteDifferencesContiguousImage(
// Sample a region of size width, height centered at x,y in image, converting
// from float to byte in the process. Samples from the first channel. Puts
// result into *pattern.
-void SampleRectangularPattern(const FloatImage &image,
- double x, double y,
+void SampleRectangularPattern(const FloatImage& image,
+ double x,
+ double y,
int width,
int height,
int pattern_stride,
- unsigned char *pattern) {
+ unsigned char* pattern) {
// There are two cases for width and height: even or odd. If it's odd, then
// the bounds [-width / 2, width / 2] works as expected. However, for even,
// this results in one extra access past the end. So use < instead of <= in
@@ -175,7 +205,7 @@ void SampleRectangularPattern(const FloatImage &image,
int end_height = (height / 2) + (height % 2);
for (int r = -height / 2; r < end_height; ++r) {
for (int c = -width / 2; c < end_width; ++c) {
- pattern[pattern_stride * (r + height / 2) + c + width / 2] =
+ pattern[pattern_stride * (r + height / 2) + c + width / 2] =
SampleLinear(image, y + r, x + c, 0) * 255.0;
}
}
@@ -195,30 +225,30 @@ inline int PadToAlignment(int x, int alignment) {
// is returned in *pattern_stride.
//
// NOTE: Caller must free *pattern with aligned_malloc() from above.
-void SampleSquarePattern(const FloatImage &image,
- double x, double y,
+void SampleSquarePattern(const FloatImage& image,
+ double x,
+ double y,
int half_width,
- unsigned char **pattern,
- int *pattern_stride) {
+ unsigned char** pattern,
+ int* pattern_stride) {
int width = 2 * half_width + 1;
// Allocate an aligned block with padding on the end so each row of the
// pattern starts on a 16-byte boundary.
*pattern_stride = PadToAlignment(width, 16);
int pattern_size_bytes = *pattern_stride * width;
- *pattern = static_cast<unsigned char *>(
- aligned_malloc(pattern_size_bytes, 16));
- SampleRectangularPattern(image, x, y, width, width,
- *pattern_stride,
- *pattern);
+ *pattern =
+ static_cast<unsigned char*>(aligned_malloc(pattern_size_bytes, 16));
+ SampleRectangularPattern(
+ image, x, y, width, width, *pattern_stride, *pattern);
}
// NOTE: Caller must free *image with aligned_malloc() from above.
-void FloatArrayToByteArrayWithPadding(const FloatImage &float_image,
- unsigned char **image,
- int *image_stride) {
+void FloatArrayToByteArrayWithPadding(const FloatImage& float_image,
+ unsigned char** image,
+ int* image_stride) {
// Allocate enough so that accessing 16 elements past the end is fine.
*image_stride = float_image.Width() + 16;
- *image = static_cast<unsigned char *>(
+ *image = static_cast<unsigned char*>(
aligned_malloc(*image_stride * float_image.Height(), 16));
for (int i = 0; i < float_image.Height(); ++i) {
for (int j = 0; j < float_image.Width(); ++j) {
@@ -235,10 +265,12 @@ void FloatArrayToByteArrayWithPadding(const FloatImage &float_image,
// values for every hypothesis looks like.
//
// TODO(keir): Priority queue for multiple hypothesis.
-bool BruteRegionTracker::Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const {
+bool BruteRegionTracker::Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const {
if (!RegionIsInBounds(image1, x1, y1, half_window_size)) {
LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1
<< ", hw=" << half_window_size << ".";
@@ -252,28 +284,28 @@ bool BruteRegionTracker::Track(const FloatImage &image1,
BlurredImageAndDerivativesChannels(image2, 0.9, &image_and_gradient2);
// Sample the pattern to get it aligned to an image grid.
- unsigned char *pattern;
+ unsigned char* pattern;
int pattern_stride;
- SampleSquarePattern(image_and_gradient1, x1, y1, half_window_size,
- &pattern,
- &pattern_stride);
+ SampleSquarePattern(
+ image_and_gradient1, x1, y1, half_window_size, &pattern, &pattern_stride);
// Convert the search area directly to bytes without sampling.
- unsigned char *search_area;
+ unsigned char* search_area;
int search_area_stride;
- FloatArrayToByteArrayWithPadding(image_and_gradient2, &search_area,
- &search_area_stride);
+ FloatArrayToByteArrayWithPadding(
+ image_and_gradient2, &search_area, &search_area_stride);
// Try all possible locations inside the search area. Yes, everywhere.
int best_i = -1, best_j = -1, best_sad = INT_MAX;
for (int i = 0; i < image2.Height() - pattern_width; ++i) {
for (int j = 0; j < image2.Width() - pattern_width; ++j) {
- int sad = SumOfAbsoluteDifferencesContiguousImage(pattern,
- pattern_width,
- pattern_width,
- pattern_stride,
- search_area + search_area_stride * i + j,
- search_area_stride);
+ int sad = SumOfAbsoluteDifferencesContiguousImage(
+ pattern,
+ pattern_width,
+ pattern_width,
+ pattern_stride,
+ search_area + search_area_stride * i + j,
+ search_area_stride);
if (sad < best_sad) {
best_i = i;
best_j = j;
@@ -309,16 +341,23 @@ bool BruteRegionTracker::Track(const FloatImage &image1,
}
Array3Df image_and_gradient1_sampled, image_and_gradient2_sampled;
- SamplePattern(image_and_gradient1, x1, y1, half_window_size, 3,
+ SamplePattern(image_and_gradient1,
+ x1,
+ y1,
+ half_window_size,
+ 3,
&image_and_gradient1_sampled);
- SamplePattern(image_and_gradient2, *x2, *y2, half_window_size, 3,
+ SamplePattern(image_and_gradient2,
+ *x2,
+ *y2,
+ half_window_size,
+ 3,
&image_and_gradient2_sampled);
// Compute the Pearson product-moment correlation coefficient to check
// for sanity.
double correlation = PearsonProductMomentCorrelation(
- image_and_gradient1_sampled,
- image_and_gradient2_sampled);
+ image_and_gradient1_sampled, image_and_gradient2_sampled);
LG << "Final correlation: " << correlation;
diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.h b/intern/libmv/libmv/tracking/brute_region_tracker.h
index a699c42ee92..183dc6df07b 100644
--- a/intern/libmv/libmv/tracking/brute_region_tracker.h
+++ b/intern/libmv/libmv/tracking/brute_region_tracker.h
@@ -27,17 +27,17 @@
namespace libmv {
struct BruteRegionTracker : public RegionTracker {
- BruteRegionTracker()
- : half_window_size(4),
- minimum_correlation(0.78) {}
+ BruteRegionTracker() : half_window_size(4), minimum_correlation(0.78) {}
virtual ~BruteRegionTracker() {}
// Tracker interface.
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const;
// No point in creating getters or setters.
int half_window_size;
diff --git a/intern/libmv/libmv/tracking/hybrid_region_tracker.cc b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc
index ea3b0f5bfc0..f0392643a6c 100644
--- a/intern/libmv/libmv/tracking/hybrid_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc
@@ -20,17 +20,19 @@
#include "libmv/tracking/hybrid_region_tracker.h"
-#include "libmv/image/image.h"
#include "libmv/image/convolve.h"
+#include "libmv/image/image.h"
#include "libmv/image/sample.h"
#include "libmv/logging/logging.h"
namespace libmv {
-bool HybridRegionTracker::Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const {
+bool HybridRegionTracker::Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const {
double x2_coarse = *x2;
double y2_coarse = *y2;
if (!coarse_tracker_->Track(image1, image2, x1, y1, &x2_coarse, &y2_coarse)) {
diff --git a/intern/libmv/libmv/tracking/hybrid_region_tracker.h b/intern/libmv/libmv/tracking/hybrid_region_tracker.h
index 967d2afd1e5..2730d2dbbf2 100644
--- a/intern/libmv/libmv/tracking/hybrid_region_tracker.h
+++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.h
@@ -21,8 +21,8 @@
#ifndef LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_
#define LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_
-#include "libmv/image/image.h"
#include "libmv/base/scoped_ptr.h"
+#include "libmv/image/image.h"
#include "libmv/tracking/region_tracker.h"
namespace libmv {
@@ -30,18 +30,19 @@ namespace libmv {
// TODO(keir): Documentation!
class HybridRegionTracker : public RegionTracker {
public:
- HybridRegionTracker(RegionTracker *coarse_tracker,
- RegionTracker *fine_tracker)
- : coarse_tracker_(coarse_tracker),
- fine_tracker_(fine_tracker) {}
+ HybridRegionTracker(RegionTracker* coarse_tracker,
+ RegionTracker* fine_tracker)
+ : coarse_tracker_(coarse_tracker), fine_tracker_(fine_tracker) {}
virtual ~HybridRegionTracker() {}
// Tracker interface.
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const;
scoped_ptr<RegionTracker> coarse_tracker_;
scoped_ptr<RegionTracker> fine_tracker_;
diff --git a/intern/libmv/libmv/tracking/kalman_filter.h b/intern/libmv/libmv/tracking/kalman_filter.h
index 9841f0e912c..b1312d0e027 100644
--- a/intern/libmv/libmv/tracking/kalman_filter.h
+++ b/intern/libmv/libmv/tracking/kalman_filter.h
@@ -19,13 +19,14 @@
// IN THE SOFTWARE.
#ifndef LIBMV_TRACKING_KALMAN_FILTER_H_
+#define LIBMV_TRACKING_KALMAN_FILTER_H_
#include "libmv/numeric/numeric.h"
namespace mv {
// A Kalman filter with order N and observation size K.
-template<typename T, int N, int K>
+template <typename T, int N, int K>
class KalmanFilter {
public:
struct State {
@@ -38,54 +39,47 @@ class KalmanFilter {
const T* observation_data,
const T* process_covariance_data,
const T* default_measurement_covariance_data)
- : state_transition_matrix_(
- Eigen::Matrix<T, N, N, Eigen::RowMajor>(state_transition_data)),
- observation_matrix_(
- Eigen::Matrix<T, K, N, Eigen::RowMajor>(observation_data)),
- process_covariance_(
- Eigen::Matrix<T, N, N, Eigen::RowMajor>(process_covariance_data)),
- default_measurement_covariance_(
- Eigen::Matrix<T, K, K, Eigen::RowMajor>(
- default_measurement_covariance_data)) {
- }
+ : state_transition_matrix_(
+ Eigen::Matrix<T, N, N, Eigen::RowMajor>(state_transition_data)),
+ observation_matrix_(
+ Eigen::Matrix<T, K, N, Eigen::RowMajor>(observation_data)),
+ process_covariance_(
+ Eigen::Matrix<T, N, N, Eigen::RowMajor>(process_covariance_data)),
+ default_measurement_covariance_(Eigen::Matrix<T, K, K, Eigen::RowMajor>(
+ default_measurement_covariance_data)) {}
- KalmanFilter(
- const Eigen::Matrix<T, N, N> &state_transition_matrix,
- const Eigen::Matrix<T, K, N> &observation_matrix,
- const Eigen::Matrix<T, N, N> &process_covariance,
- const Eigen::Matrix<T, K, K> &default_measurement_covariance)
- : state_transition_matrix_(state_transition_matrix),
- observation_matrix_(observation_matrix),
- process_covariance_(process_covariance),
- default_measurement_covariance_(default_measurement_covariance) {
- }
+ KalmanFilter(const Eigen::Matrix<T, N, N>& state_transition_matrix,
+ const Eigen::Matrix<T, K, N>& observation_matrix,
+ const Eigen::Matrix<T, N, N>& process_covariance,
+ const Eigen::Matrix<T, K, K>& default_measurement_covariance)
+ : state_transition_matrix_(state_transition_matrix),
+ observation_matrix_(observation_matrix),
+ process_covariance_(process_covariance),
+ default_measurement_covariance_(default_measurement_covariance) {}
// Advances the system according to the current state estimate.
- void Step(State *state) const {
+ void Step(State* state) const {
state->mean = state_transition_matrix_ * state->mean;
- state->covariance = state_transition_matrix_ *
- state->covariance *
- state_transition_matrix_.transpose() +
+ state->covariance = state_transition_matrix_ * state->covariance *
+ state_transition_matrix_.transpose() +
process_covariance_;
}
// Updates a state with a new measurement.
- void Update(const Eigen::Matrix<T, K, 1> &measurement_mean,
- const Eigen::Matrix<T, K, K> &measurement_covariance,
- State *state) const {
+ void Update(const Eigen::Matrix<T, K, 1>& measurement_mean,
+ const Eigen::Matrix<T, K, K>& measurement_covariance,
+ State* state) const {
// Calculate the innovation, which is a distribution over prediction error.
- Eigen::Matrix<T, K, 1> innovation_mean = measurement_mean -
- observation_matrix_ *
- state->mean;
+ Eigen::Matrix<T, K, 1> innovation_mean =
+ measurement_mean - observation_matrix_ * state->mean;
Eigen::Matrix<T, K, K> innovation_covariance =
- observation_matrix_ *
- state->covariance *
- observation_matrix_.transpose() +
+ observation_matrix_ * state->covariance *
+ observation_matrix_.transpose() +
measurement_covariance;
// Calculate the Kalman gain.
Eigen::Matrix<T, 6, 2> kalman_gain = state->covariance *
- observation_matrix_.transpose() *
+ observation_matrix_.transpose() *
innovation_covariance.inverse();
// Update the state mean and covariance.
@@ -95,8 +89,8 @@ class KalmanFilter {
state->covariance;
}
- void Update(State *state,
- const Eigen::Matrix<T, K, 1> &measurement_mean) const {
+ void Update(State* state,
+ const Eigen::Matrix<T, K, 1>& measurement_mean) const {
Update(state, measurement_mean, default_measurement_covariance_);
}
diff --git a/intern/libmv/libmv/tracking/klt_region_tracker.cc b/intern/libmv/libmv/tracking/klt_region_tracker.cc
index dbbf9f0b996..df1ded65489 100644
--- a/intern/libmv/libmv/tracking/klt_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/klt_region_tracker.cc
@@ -20,10 +20,10 @@
#include "libmv/tracking/klt_region_tracker.h"
-#include "libmv/logging/logging.h"
-#include "libmv/image/image.h"
#include "libmv/image/convolve.h"
+#include "libmv/image/image.h"
#include "libmv/image/sample.h"
+#include "libmv/logging/logging.h"
namespace libmv {
@@ -33,16 +33,18 @@ namespace libmv {
// TODO(keir): The calls to SampleLinear() do boundary checking that should
// instead happen outside the loop. Since this is the innermost loop, the extra
// bounds checking hurts performance.
-static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
- const Array3Df &image_and_gradient2,
- double x1, double y1,
- double x2, double y2,
+static void ComputeTrackingEquation(const Array3Df& image_and_gradient1,
+ const Array3Df& image_and_gradient2,
+ double x1,
+ double y1,
+ double x2,
+ double y2,
int half_width,
- float *gxx,
- float *gxy,
- float *gyy,
- float *ex,
- float *ey) {
+ float* gxx,
+ float* gxy,
+ float* gyy,
+ float* ex,
+ float* ey) {
*gxx = *gxy = *gyy = 0;
*ex = *ey = 0;
for (int r = -half_width; r <= half_width; ++r) {
@@ -51,8 +53,8 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
float yy1 = y1 + r;
float xx2 = x2 + c;
float yy2 = y2 + r;
- float I = SampleLinear(image_and_gradient1, yy1, xx1, 0);
- float J = SampleLinear(image_and_gradient2, yy2, xx2, 0);
+ float I = SampleLinear(image_and_gradient1, yy1, xx1, 0);
+ float J = SampleLinear(image_and_gradient2, yy2, xx2, 0);
float gx = SampleLinear(image_and_gradient2, yy2, xx2, 1);
float gy = SampleLinear(image_and_gradient2, yy2, xx2, 2);
*gxx += gx * gx;
@@ -64,22 +66,21 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
}
}
-static bool RegionIsInBounds(const FloatImage &image1,
- double x, double y,
- int half_window_size) {
+static bool RegionIsInBounds(const FloatImage& image1,
+ double x,
+ double y,
+ int half_window_size) {
// Check the minimum coordinates.
int min_x = floor(x) - half_window_size - 1;
int min_y = floor(y) - half_window_size - 1;
- if (min_x < 0.0 ||
- min_y < 0.0) {
+ if (min_x < 0.0 || min_y < 0.0) {
return false;
}
// Check the maximum coordinates.
int max_x = ceil(x) + half_window_size + 1;
int max_y = ceil(y) + half_window_size + 1;
- if (max_x > image1.cols() ||
- max_y > image1.rows()) {
+ if (max_x > image1.cols() || max_y > image1.rows()) {
return false;
}
@@ -87,10 +88,12 @@ static bool RegionIsInBounds(const FloatImage &image1,
return true;
}
-bool KltRegionTracker::Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const {
+bool KltRegionTracker::Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const {
if (!RegionIsInBounds(image1, x1, y1, half_window_size)) {
LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1
<< ", hw=" << half_window_size << ".";
@@ -116,10 +119,16 @@ bool KltRegionTracker::Track(const FloatImage &image1,
float gxx, gxy, gyy, ex, ey;
ComputeTrackingEquation(image_and_gradient1,
image_and_gradient2,
- x1, y1,
- *x2, *y2,
+ x1,
+ y1,
+ *x2,
+ *y2,
half_window_size,
- &gxx, &gxy, &gyy, &ex, &ey);
+ &gxx,
+ &gxy,
+ &gyy,
+ &ex,
+ &ey);
// Solve the tracking equation
//
diff --git a/intern/libmv/libmv/tracking/klt_region_tracker.h b/intern/libmv/libmv/tracking/klt_region_tracker.h
index 43977757084..07ed1b7155c 100644
--- a/intern/libmv/libmv/tracking/klt_region_tracker.h
+++ b/intern/libmv/libmv/tracking/klt_region_tracker.h
@@ -37,10 +37,12 @@ struct KltRegionTracker : public RegionTracker {
virtual ~KltRegionTracker() {}
// Tracker interface.
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const;
// No point in creating getters or setters.
int half_window_size;
diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc
index 4db501050f3..52764a535e0 100644
--- a/intern/libmv/libmv/tracking/pyramid_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc
@@ -29,8 +29,9 @@
namespace libmv {
-static void MakePyramid(const FloatImage &image, int num_levels,
- std::vector<FloatImage> *pyramid) {
+static void MakePyramid(const FloatImage& image,
+ int num_levels,
+ std::vector<FloatImage>* pyramid) {
pyramid->resize(num_levels);
(*pyramid)[0] = image;
for (int i = 1; i < num_levels; ++i) {
@@ -38,10 +39,12 @@ static void MakePyramid(const FloatImage &image, int num_levels,
}
}
-bool PyramidRegionTracker::Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const {
+bool PyramidRegionTracker::Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const {
// Shrink the guessed x and y location to match the coarsest level + 1 (which
// when gets corrected in the loop).
*x2 /= pow(2., num_levels_);
@@ -71,8 +74,8 @@ bool PyramidRegionTracker::Track(const FloatImage &image1,
// Track the point on this level with the base tracker.
LG << "Tracking on level " << i;
- bool succeeded = tracker_->Track(pyramid1[i], pyramid2[i], xx, yy,
- &x2_new, &y2_new);
+ bool succeeded =
+ tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, &x2_new, &y2_new);
if (!succeeded) {
if (i == 0) {
diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker.h b/intern/libmv/libmv/tracking/pyramid_region_tracker.h
index 1f9675469f4..5fe21c95904 100644
--- a/intern/libmv/libmv/tracking/pyramid_region_tracker.h
+++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.h
@@ -21,21 +21,24 @@
#ifndef LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
#define LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
-#include "libmv/image/image.h"
#include "libmv/base/scoped_ptr.h"
+#include "libmv/image/image.h"
#include "libmv/tracking/region_tracker.h"
namespace libmv {
class PyramidRegionTracker : public RegionTracker {
public:
- PyramidRegionTracker(RegionTracker *tracker, int num_levels)
+ PyramidRegionTracker(RegionTracker* tracker, int num_levels)
: tracker_(tracker), num_levels_(num_levels) {}
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const;
+
private:
scoped_ptr<RegionTracker> tracker_;
int num_levels_;
diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
index d90a1012237..2fcf292e404 100644
--- a/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
+++ b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
@@ -19,8 +19,8 @@
// IN THE SOFTWARE.
#include "libmv/tracking/pyramid_region_tracker.h"
-#include "libmv/tracking/klt_region_tracker.h"
#include "libmv/image/image.h"
+#include "libmv/tracking/klt_region_tracker.h"
#include "testing/testing.h"
namespace libmv {
@@ -55,8 +55,7 @@ TEST(PyramidKltRegionTracker, Track) {
KltRegionTracker tracker;
tracker.half_window_size = half_window_size;
- EXPECT_FALSE(tracker.Track(image1, image2, x1, y1,
- &x2_actual, &y2_actual));
+ EXPECT_FALSE(tracker.Track(image1, image2, x1, y1, &x2_actual, &y2_actual));
}
// Verify that it works with the pyramid tracker.
@@ -64,12 +63,11 @@ TEST(PyramidKltRegionTracker, Track) {
double x2_actual = x1;
double y2_actual = y1;
- KltRegionTracker *klt_tracker = new KltRegionTracker;
+ KltRegionTracker* klt_tracker = new KltRegionTracker;
klt_tracker->half_window_size = half_window_size;
PyramidRegionTracker tracker(klt_tracker, 3);
- EXPECT_TRUE(tracker.Track(image1, image2, x1, y1,
- &x2_actual, &y2_actual));
+ EXPECT_TRUE(tracker.Track(image1, image2, x1, y1, &x2_actual, &y2_actual));
EXPECT_NEAR(x2_actual, x2, 0.001);
EXPECT_NEAR(y2_actual, y2, 0.001);
diff --git a/intern/libmv/libmv/tracking/region_tracker.h b/intern/libmv/libmv/tracking/region_tracker.h
index 4f7574df1a3..e753ac8be6c 100644
--- a/intern/libmv/libmv/tracking/region_tracker.h
+++ b/intern/libmv/libmv/tracking/region_tracker.h
@@ -37,10 +37,12 @@ class RegionTracker {
image2. If no guess is available, (\a x1, \a y1) is a good start. Returns
true on success, false otherwise
*/
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const = 0;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const = 0;
};
} // namespace libmv
diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.cc b/intern/libmv/libmv/tracking/retrack_region_tracker.cc
index 4d230086d28..9152078053c 100644
--- a/intern/libmv/libmv/tracking/retrack_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/retrack_region_tracker.cc
@@ -25,10 +25,12 @@
namespace libmv {
-bool RetrackRegionTracker::Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const {
+bool RetrackRegionTracker::Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const {
// Track forward, getting x2 and y2.
if (!tracker_->Track(image1, image2, x1, y1, x2, y2)) {
return false;
diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.h b/intern/libmv/libmv/tracking/retrack_region_tracker.h
index ab05f320834..504cf697349 100644
--- a/intern/libmv/libmv/tracking/retrack_region_tracker.h
+++ b/intern/libmv/libmv/tracking/retrack_region_tracker.h
@@ -21,8 +21,8 @@
#ifndef LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
#define LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
-#include "libmv/image/image.h"
#include "libmv/base/scoped_ptr.h"
+#include "libmv/image/image.h"
#include "libmv/tracking/region_tracker.h"
namespace libmv {
@@ -31,13 +31,16 @@ namespace libmv {
// track that doesn't track backwards to the starting point.
class RetrackRegionTracker : public RegionTracker {
public:
- RetrackRegionTracker(RegionTracker *tracker, double tolerance)
+ RetrackRegionTracker(RegionTracker* tracker, double tolerance)
: tracker_(tracker), tolerance_(tolerance) {}
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const;
+
private:
scoped_ptr<RegionTracker> tracker_;
double tolerance_;
diff --git a/intern/libmv/libmv/tracking/track_region.cc b/intern/libmv/libmv/tracking/track_region.cc
index 895c9a1e23d..b9bd70e1405 100644
--- a/intern/libmv/libmv/tracking/track_region.cc
+++ b/intern/libmv/libmv/tracking/track_region.cc
@@ -27,14 +27,14 @@
#include "libmv/tracking/track_region.h"
-#include <Eigen/SVD>
#include <Eigen/QR>
+#include <Eigen/SVD>
#include <iostream>
#include "ceres/ceres.h"
-#include "libmv/logging/logging.h"
+#include "libmv/image/convolve.h"
#include "libmv/image/image.h"
#include "libmv/image/sample.h"
-#include "libmv/image/convolve.h"
+#include "libmv/logging/logging.h"
#include "libmv/multiview/homography.h"
#include "libmv/numeric/numeric.h"
@@ -44,57 +44,45 @@
namespace ceres {
// A jet traits class to make it easier to work with mixed auto / numeric diff.
-template<typename T>
+template <typename T>
struct JetOps {
- static bool IsScalar() {
- return true;
- }
- static T GetScalar(const T& t) {
- return t;
- }
- static void SetScalar(const T& scalar, T* t) {
- *t = scalar;
- }
- static void ScaleDerivative(double scale_by, T *value) {
+ static bool IsScalar() { return true; }
+ static T GetScalar(const T& t) { return t; }
+ static void SetScalar(const T& scalar, T* t) { *t = scalar; }
+ static void ScaleDerivative(double scale_by, T* value) {
// For double, there is no derivative to scale.
- (void) scale_by; // Ignored.
- (void) value; // Ignored.
+ (void)scale_by; // Ignored.
+ (void)value; // Ignored.
}
};
-template<typename T, int N>
-struct JetOps<Jet<T, N> > {
- static bool IsScalar() {
- return false;
- }
- static T GetScalar(const Jet<T, N>& t) {
- return t.a;
- }
- static void SetScalar(const T& scalar, Jet<T, N>* t) {
- t->a = scalar;
- }
- static void ScaleDerivative(double scale_by, Jet<T, N> *value) {
+template <typename T, int N>
+struct JetOps<Jet<T, N>> {
+ static bool IsScalar() { return false; }
+ static T GetScalar(const Jet<T, N>& t) { return t.a; }
+ static void SetScalar(const T& scalar, Jet<T, N>* t) { t->a = scalar; }
+ static void ScaleDerivative(double scale_by, Jet<T, N>* value) {
value->v *= scale_by;
}
};
-template<typename FunctionType, int kNumArgs, typename ArgumentType>
+template <typename FunctionType, int kNumArgs, typename ArgumentType>
struct Chain {
- static ArgumentType Rule(const FunctionType &f,
+ static ArgumentType Rule(const FunctionType& f,
const FunctionType dfdx[kNumArgs],
const ArgumentType x[kNumArgs]) {
// In the default case of scalars, there's nothing to do since there are no
// derivatives to propagate.
- (void) dfdx; // Ignored.
- (void) x; // Ignored.
+ (void)dfdx; // Ignored.
+ (void)x; // Ignored.
return f;
}
};
// XXX Add documentation here!
-template<typename FunctionType, int kNumArgs, typename T, int N>
-struct Chain<FunctionType, kNumArgs, Jet<T, N> > {
- static Jet<T, N> Rule(const FunctionType &f,
+template <typename FunctionType, int kNumArgs, typename T, int N>
+struct Chain<FunctionType, kNumArgs, Jet<T, N>> {
+ static Jet<T, N> Rule(const FunctionType& f,
const FunctionType dfdx[kNumArgs],
const Jet<T, N> x[kNumArgs]) {
// x is itself a function of another variable ("z"); what this function
@@ -107,8 +95,8 @@ struct Chain<FunctionType, kNumArgs, Jet<T, N> > {
}
// Map the input gradient dfdx into an Eigen row vector.
- Eigen::Map<const Eigen::Matrix<FunctionType, 1, kNumArgs> >
- vector_dfdx(dfdx, 1, kNumArgs);
+ Eigen::Map<const Eigen::Matrix<FunctionType, 1, kNumArgs>> vector_dfdx(
+ dfdx, 1, kNumArgs);
// Now apply the chain rule to obtain df/dz. Combine the derivative with
// the scalar part to obtain f with full derivative information.
@@ -123,12 +111,13 @@ struct Chain<FunctionType, kNumArgs, Jet<T, N> > {
namespace libmv {
+using ceres::Chain;
using ceres::Jet;
using ceres::JetOps;
-using ceres::Chain;
TrackRegionOptions::TrackRegionOptions()
- : mode(TRANSLATION),
+ : direction(FORWARD),
+ mode(TRANSLATION),
minimum_correlation(0),
max_iterations(20),
use_esm(true),
@@ -144,17 +133,12 @@ TrackRegionOptions::TrackRegionOptions()
namespace {
// TODO(keir): Consider adding padding.
-template<typename T>
-bool InBounds(const FloatImage &image,
- const T &x,
- const T &y) {
- return 0.0 <= x && x < image.Width() &&
- 0.0 <= y && y < image.Height();
+template <typename T>
+bool InBounds(const FloatImage& image, const T& x, const T& y) {
+ return 0.0 <= x && x < image.Width() && 0.0 <= y && y < image.Height();
}
-bool AllInBounds(const FloatImage &image,
- const double *x,
- const double *y) {
+bool AllInBounds(const FloatImage& image, const double* x, const double* y) {
for (int i = 0; i < 4; ++i) {
if (!InBounds(image, x[i], y[i])) {
return false;
@@ -166,10 +150,10 @@ bool AllInBounds(const FloatImage &image,
// Sample the image at position (x, y) but use the gradient, if present, to
// propagate derivatives from x and y. This is needed to integrate the numeric
// image gradients with Ceres's autodiff framework.
-template<typename T>
-static T SampleWithDerivative(const FloatImage &image_and_gradient,
- const T &x,
- const T &y) {
+template <typename T>
+static T SampleWithDerivative(const FloatImage& image_and_gradient,
+ const T& x,
+ const T& y) {
float scalar_x = JetOps<T>::GetScalar(x);
float scalar_y = JetOps<T>::GetScalar(y);
@@ -184,18 +168,23 @@ static T SampleWithDerivative(const FloatImage &image_and_gradient,
// For the derivative case, sample the gradient as well.
SampleLinear(image_and_gradient, scalar_y, scalar_x, sample);
}
- T xy[2] = { x, y };
+ T xy[2] = {x, y};
return Chain<float, 2, T>::Rule(sample[0], sample + 1, xy);
}
-template<typename Warp>
+template <typename Warp>
class TerminationCheckingCallback : public ceres::IterationCallback {
public:
- TerminationCheckingCallback(const TrackRegionOptions &options,
+ TerminationCheckingCallback(const TrackRegionOptions& options,
const FloatImage& image2,
- const Warp &warp,
- const double *x1, const double *y1)
- : options_(options), image2_(image2), warp_(warp), x1_(x1), y1_(y1),
+ const Warp& warp,
+ const double* x1,
+ const double* y1)
+ : options_(options),
+ image2_(image2),
+ warp_(warp),
+ x1_(x1),
+ y1_(y1),
have_last_successful_step_(false) {}
virtual ceres::CallbackReturnType operator()(
@@ -229,7 +218,7 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
for (int i = 0; i < 4; ++i) {
double dx = x2[i] - x2_last_successful_[i];
double dy = y2[i] - y2_last_successful_[i];
- double change_pixels = dx*dx + dy*dy;
+ double change_pixels = dx * dx + dy * dy;
if (change_pixels > max_change_pixels) {
max_change_pixels = change_pixels;
}
@@ -255,27 +244,27 @@ class TerminationCheckingCallback : public ceres::IterationCallback {
}
private:
- const TrackRegionOptions &options_;
- const FloatImage &image2_;
- const Warp &warp_;
- const double *x1_;
- const double *y1_;
+ const TrackRegionOptions& options_;
+ const FloatImage& image2_;
+ const Warp& warp_;
+ const double* x1_;
+ const double* y1_;
bool have_last_successful_step_;
double x2_last_successful_[4];
double y2_last_successful_[4];
};
-template<typename Warp>
+template <typename Warp>
class PixelDifferenceCostFunctor {
public:
- PixelDifferenceCostFunctor(const TrackRegionOptions &options,
- const FloatImage &image_and_gradient1,
- const FloatImage &image_and_gradient2,
- const Mat3 &canonical_to_image1,
+ PixelDifferenceCostFunctor(const TrackRegionOptions& options,
+ const FloatImage& image_and_gradient1,
+ const FloatImage& image_and_gradient2,
+ const Mat3& canonical_to_image1,
int num_samples_x,
int num_samples_y,
- const Warp &warp)
+ const Warp& warp)
: options_(options),
image_and_gradient1_(image_and_gradient1),
image_and_gradient2_(image_and_gradient2),
@@ -322,8 +311,8 @@ class PixelDifferenceCostFunctor {
src_mean_ /= num_samples;
}
- template<typename T>
- bool operator()(const T *warp_parameters, T *residuals) const {
+ template <typename T>
+ bool operator()(const T* warp_parameters, T* residuals) const {
if (options_.image1_mask != NULL) {
VLOG(2) << "Using a mask.";
}
@@ -333,8 +322,7 @@ class PixelDifferenceCostFunctor {
T dst_mean = T(1.0);
if (options_.use_normalized_intensities) {
- ComputeNormalizingCoefficient(warp_parameters,
- &dst_mean);
+ ComputeNormalizingCoefficient(warp_parameters, &dst_mean);
}
int cursor = 0;
@@ -374,9 +362,8 @@ class PixelDifferenceCostFunctor {
&image2_position[1]);
// Sample the destination, propagating derivatives.
- T dst_sample = SampleWithDerivative(image_and_gradient2_,
- image2_position[0],
- image2_position[1]);
+ T dst_sample = SampleWithDerivative(
+ image_and_gradient2_, image2_position[0], image2_position[1]);
// Sample the source. This is made complicated by ESM mode.
T src_sample;
@@ -386,8 +373,8 @@ class PixelDifferenceCostFunctor {
// better convergence. Copy the derivative of the warp parameters
// onto the jets for the image1 position. This is the ESM hack.
T image1_position_jet[2] = {
- image2_position[0], // Order is x, y. This matches the
- image2_position[1] // derivative order in the patch.
+ image2_position[0], // Order is x, y. This matches the
+ image2_position[1] // derivative order in the patch.
};
JetOps<T>::SetScalar(image1_position[0], image1_position_jet + 0);
JetOps<T>::SetScalar(image1_position[1], image1_position_jet + 1);
@@ -433,9 +420,9 @@ class PixelDifferenceCostFunctor {
}
// For normalized matching, the average and
- template<typename T>
- void ComputeNormalizingCoefficient(const T *warp_parameters,
- T *dst_mean) const {
+ template <typename T>
+ void ComputeNormalizingCoefficient(const T* warp_parameters,
+ T* dst_mean) const {
*dst_mean = T(0.0);
double num_samples = 0.0;
for (int r = 0; r < num_samples_y_; ++r) {
@@ -462,14 +449,12 @@ class PixelDifferenceCostFunctor {
&image2_position[0],
&image2_position[1]);
-
// Sample the destination, propagating derivatives.
// TODO(keir): This accumulation can, surprisingly, be done as a
// pre-pass by using integral images. This is complicated by the need
// to store the jets in the integral image, but it is possible.
- T dst_sample = SampleWithDerivative(image_and_gradient2_,
- image2_position[0],
- image2_position[1]);
+ T dst_sample = SampleWithDerivative(
+ image_and_gradient2_, image2_position[0], image2_position[1]);
// Weight the sample by the mask, if one is present.
if (options_.image1_mask != NULL) {
@@ -486,10 +471,10 @@ class PixelDifferenceCostFunctor {
// TODO(keir): Consider also computing the cost here.
double PearsonProductMomentCorrelationCoefficient(
- const double *warp_parameters) const {
+ const double* warp_parameters) const {
for (int i = 0; i < Warp::NUM_PARAMETERS; ++i) {
- VLOG(2) << "Correlation warp_parameters[" << i << "]: "
- << warp_parameters[i];
+ VLOG(2) << "Correlation warp_parameters[" << i
+ << "]: " << warp_parameters[i];
}
// The single-pass PMCC computation is somewhat numerically unstable, but
@@ -537,9 +522,9 @@ class PixelDifferenceCostFunctor {
}
sX += x;
sY += y;
- sXX += x*x;
- sYY += y*y;
- sXY += x*y;
+ sXX += x * x;
+ sYY += y * y;
+ sXY += x * y;
}
}
// Normalize.
@@ -549,25 +534,24 @@ class PixelDifferenceCostFunctor {
sYY /= num_samples;
sXY /= num_samples;
- double var_x = sXX - sX*sX;
- double var_y = sYY - sY*sY;
- double covariance_xy = sXY - sX*sY;
+ double var_x = sXX - sX * sX;
+ double var_y = sYY - sY * sY;
+ double covariance_xy = sXY - sX * sY;
double correlation = covariance_xy / sqrt(var_x * var_y);
- LG << "Covariance xy: " << covariance_xy
- << ", var 1: " << var_x << ", var 2: " << var_y
- << ", correlation: " << correlation;
+ LG << "Covariance xy: " << covariance_xy << ", var 1: " << var_x
+ << ", var 2: " << var_y << ", correlation: " << correlation;
return correlation;
}
private:
- const TrackRegionOptions &options_;
- const FloatImage &image_and_gradient1_;
- const FloatImage &image_and_gradient2_;
- const Mat3 &canonical_to_image1_;
+ const TrackRegionOptions& options_;
+ const FloatImage& image_and_gradient1_;
+ const FloatImage& image_and_gradient2_;
+ const Mat3& canonical_to_image1_;
int num_samples_x_;
int num_samples_y_;
- const Warp &warp_;
+ const Warp& warp_;
double src_mean_;
FloatImage pattern_and_gradient_;
@@ -579,15 +563,15 @@ class PixelDifferenceCostFunctor {
FloatImage pattern_mask_;
};
-template<typename Warp>
+template <typename Warp>
class WarpRegularizingCostFunctor {
public:
- WarpRegularizingCostFunctor(const TrackRegionOptions &options,
- const double *x1,
- const double *y1,
- const double *x2_original,
- const double *y2_original,
- const Warp &warp)
+ WarpRegularizingCostFunctor(const TrackRegionOptions& options,
+ const double* x1,
+ const double* y1,
+ const double* x2_original,
+ const double* y2_original,
+ const Warp& warp)
: options_(options),
x1_(x1),
y1_(y1),
@@ -606,11 +590,11 @@ class WarpRegularizingCostFunctor {
original_centroid_[1] /= 4;
}
- template<typename T>
- bool operator()(const T *warp_parameters, T *residuals) const {
- T dst_centroid[2] = { T(0.0), T(0.0) };
+ template <typename T>
+ bool operator()(const T* warp_parameters, T* residuals) const {
+ T dst_centroid[2] = {T(0.0), T(0.0)};
for (int i = 0; i < 4; ++i) {
- T image1_position[2] = { T(x1_[i]), T(y1_[i]) };
+ T image1_position[2] = {T(x1_[i]), T(y1_[i])};
T image2_position[2];
warp_.Forward(warp_parameters,
T(x1_[i]),
@@ -643,28 +627,30 @@ class WarpRegularizingCostFunctor {
return true;
}
- const TrackRegionOptions &options_;
- const double *x1_;
- const double *y1_;
- const double *x2_original_;
- const double *y2_original_;
+ const TrackRegionOptions& options_;
+ const double* x1_;
+ const double* y1_;
+ const double* x2_original_;
+ const double* y2_original_;
double original_centroid_[2];
- const Warp &warp_;
+ const Warp& warp_;
};
// Compute the warp from rectangular coordinates, where one corner is the
// origin, and the opposite corner is at (num_samples_x, num_samples_y).
-Mat3 ComputeCanonicalHomography(const double *x1,
- const double *y1,
+Mat3 ComputeCanonicalHomography(const double* x1,
+ const double* y1,
int num_samples_x,
int num_samples_y) {
Mat canonical(2, 4);
- canonical << 0, num_samples_x, num_samples_x, 0,
- 0, 0, num_samples_y, num_samples_y;
+ canonical << 0, num_samples_x, num_samples_x, 0, 0, 0, num_samples_y,
+ num_samples_y;
Mat xy1(2, 4);
+ // clang-format off
xy1 << x1[0], x1[1], x1[2], x1[3],
y1[0], y1[1], y1[2], y1[3];
+ // clang-format om
Mat3 H;
if (!Homography2DFromCorrespondencesLinear(canonical, xy1, &H, 1e-12)) {
@@ -675,7 +661,7 @@ Mat3 ComputeCanonicalHomography(const double *x1,
class Quad {
public:
- Quad(const double *x, const double *y) : x_(x), y_(y) {
+ Quad(const double* x, const double* y) : x_(x), y_(y) {
// Compute the centroid and store it.
centroid_ = Vec2(0.0, 0.0);
for (int i = 0; i < 4; ++i) {
@@ -685,9 +671,7 @@ class Quad {
}
// The centroid of the four points representing the quad.
- const Vec2& Centroid() const {
- return centroid_;
- }
+ const Vec2& Centroid() const { return centroid_; }
// The average magnitude of the four points relative to the centroid.
double Scale() const {
@@ -703,22 +687,24 @@ class Quad {
}
private:
- const double *x_;
- const double *y_;
+ const double* x_;
+ const double* y_;
Vec2 centroid_;
};
struct TranslationWarp {
- TranslationWarp(const double *x1, const double *y1,
- const double *x2, const double *y2) {
+ TranslationWarp(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2) {
Vec2 t = Quad(x2, y2).Centroid() - Quad(x1, y1).Centroid();
parameters[0] = t[0];
parameters[1] = t[1];
}
- template<typename T>
- void Forward(const T *warp_parameters,
- const T &x1, const T& y1, T *x2, T* y2) const {
+ template <typename T>
+ void Forward(
+ const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const {
*x2 = x1 + warp_parameters[0];
*y2 = y1 + warp_parameters[1];
}
@@ -729,8 +715,10 @@ struct TranslationWarp {
};
struct TranslationScaleWarp {
- TranslationScaleWarp(const double *x1, const double *y1,
- const double *x2, const double *y2)
+ TranslationScaleWarp(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2)
: q1(x1, y1) {
Quad q2(x2, y2);
@@ -746,9 +734,9 @@ struct TranslationScaleWarp {
// The strange way of parameterizing the translation and scaling is to make
// the knobs that the optimizer sees easy to adjust. This is less important
// for the scaling case than the rotation case.
- template<typename T>
- void Forward(const T *warp_parameters,
- const T &x1, const T& y1, T *x2, T* y2) const {
+ template <typename T>
+ void Forward(
+ const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const {
// Make the centroid of Q1 the origin.
const T x1_origin = x1 - q1.Centroid()(0);
const T y1_origin = y1 - q1.Centroid()(1);
@@ -775,15 +763,17 @@ struct TranslationScaleWarp {
};
// Assumes the given points are already zero-centroid and the same size.
-Mat2 OrthogonalProcrustes(const Mat2 &correlation_matrix) {
+Mat2 OrthogonalProcrustes(const Mat2& correlation_matrix) {
Eigen::JacobiSVD<Mat2> svd(correlation_matrix,
Eigen::ComputeFullU | Eigen::ComputeFullV);
return svd.matrixV() * svd.matrixU().transpose();
}
struct TranslationRotationWarp {
- TranslationRotationWarp(const double *x1, const double *y1,
- const double *x2, const double *y2)
+ TranslationRotationWarp(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2)
: q1(x1, y1) {
Quad q2(x2, y2);
@@ -816,9 +806,9 @@ struct TranslationRotationWarp {
//
// Instead, use the parameterization below that offers a parameterization
// that exposes the degrees of freedom in a way amenable to optimization.
- template<typename T>
- void Forward(const T *warp_parameters,
- const T &x1, const T& y1, T *x2, T* y2) const {
+ template <typename T>
+ void Forward(
+ const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const {
// Make the centroid of Q1 the origin.
const T x1_origin = x1 - q1.Centroid()(0);
const T y1_origin = y1 - q1.Centroid()(1);
@@ -847,8 +837,10 @@ struct TranslationRotationWarp {
};
struct TranslationRotationScaleWarp {
- TranslationRotationScaleWarp(const double *x1, const double *y1,
- const double *x2, const double *y2)
+ TranslationRotationScaleWarp(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2)
: q1(x1, y1) {
Quad q2(x2, y2);
@@ -884,9 +876,9 @@ struct TranslationRotationScaleWarp {
//
// Instead, use the parameterization below that offers a parameterization
// that exposes the degrees of freedom in a way amenable to optimization.
- template<typename T>
- void Forward(const T *warp_parameters,
- const T &x1, const T& y1, T *x2, T* y2) const {
+ template <typename T>
+ void Forward(
+ const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const {
// Make the centroid of Q1 the origin.
const T x1_origin = x1 - q1.Centroid()(0);
const T y1_origin = y1 - q1.Centroid()(1);
@@ -921,8 +913,10 @@ struct TranslationRotationScaleWarp {
};
struct AffineWarp {
- AffineWarp(const double *x1, const double *y1,
- const double *x2, const double *y2)
+ AffineWarp(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2)
: q1(x1, y1) {
Quad q2(x2, y2);
@@ -938,8 +932,8 @@ struct AffineWarp {
Vec2 v1 = q1.CornerRelativeToCentroid(i);
Vec2 v2 = q2.CornerRelativeToCentroid(i);
- Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0;
- Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1];
+ Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0;
+ Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1];
Q2(2 * i + 0) = v2[0];
Q2(2 * i + 1) = v2[1];
@@ -957,8 +951,8 @@ struct AffineWarp {
}
// See comments in other parameterizations about why the centroid is used.
- template<typename T>
- void Forward(const T *p, const T &x1, const T& y1, T *x2, T* y2) const {
+ template <typename T>
+ void Forward(const T* p, const T& x1, const T& y1, T* x2, T* y2) const {
// Make the centroid of Q1 the origin.
const T x1_origin = x1 - q1.Centroid()(0);
const T y1_origin = y1 - q1.Centroid()(1);
@@ -985,15 +979,21 @@ struct AffineWarp {
};
struct HomographyWarp {
- HomographyWarp(const double *x1, const double *y1,
- const double *x2, const double *y2) {
+ HomographyWarp(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2) {
Mat quad1(2, 4);
+ // clang-format off
quad1 << x1[0], x1[1], x1[2], x1[3],
y1[0], y1[1], y1[2], y1[3];
+ // clang-format on
Mat quad2(2, 4);
+ // clang-format off
quad2 << x2[0], x2[1], x2[2], x2[3],
y2[0], y2[1], y2[2], y2[3];
+ // clang-format on
Mat3 H;
if (!Homography2DFromCorrespondencesLinear(quad1, quad2, &H, 1e-12)) {
@@ -1014,13 +1014,12 @@ struct HomographyWarp {
}
}
- template<typename T>
- static void Forward(const T *p,
- const T &x1, const T& y1, T *x2, T* y2) {
+ template <typename T>
+ static void Forward(const T* p, const T& x1, const T& y1, T* x2, T* y2) {
// Homography warp with manual 3x3 matrix multiply.
- const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2];
- const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5];
- const T zz2 = p[6] * x1 + p[7] * y1 + 1.0;
+ const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2];
+ const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5];
+ const T zz2 = p[6] * x1 + p[7] * y1 + 1.0;
*x2 = xx2 / zz2;
*y2 = yy2 / zz2;
}
@@ -1036,11 +1035,14 @@ struct HomographyWarp {
//
// The idea is to take the maximum x or y distance. This may be oversampling.
// TODO(keir): Investigate the various choices; perhaps average is better?
-void PickSampling(const double *x1, const double *y1,
- const double *x2, const double *y2,
- int *num_samples_x, int *num_samples_y) {
- (void) x2; // Ignored.
- (void) y2; // Ignored.
+void PickSampling(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2,
+ int* num_samples_x,
+ int* num_samples_y) {
+ (void)x2; // Ignored.
+ (void)y2; // Ignored.
Vec2 a0(x1[0], y1[0]);
Vec2 a1(x1[1], y1[1]);
@@ -1053,18 +1055,10 @@ void PickSampling(const double *x1, const double *y1,
Vec2 b3(x1[3], y1[3]);
double x_dimensions[4] = {
- (a1 - a0).norm(),
- (a3 - a2).norm(),
- (b1 - b0).norm(),
- (b3 - b2).norm()
- };
+ (a1 - a0).norm(), (a3 - a2).norm(), (b1 - b0).norm(), (b3 - b2).norm()};
double y_dimensions[4] = {
- (a3 - a0).norm(),
- (a1 - a2).norm(),
- (b3 - b0).norm(),
- (b1 - b2).norm()
- };
+ (a3 - a0).norm(), (a1 - a2).norm(), (b3 - b0).norm(), (b1 - b2).norm()};
const double kScaleFactor = 1.0;
*num_samples_x = static_cast<int>(
kScaleFactor * *std::max_element(x_dimensions, x_dimensions + 4));
@@ -1074,17 +1068,18 @@ void PickSampling(const double *x1, const double *y1,
<< ", num_samples_y: " << *num_samples_y;
}
-bool SearchAreaTooBigForDescent(const FloatImage &image2,
- const double *x2, const double *y2) {
+bool SearchAreaTooBigForDescent(const FloatImage& image2,
+ const double* x2,
+ const double* y2) {
// TODO(keir): Check the bounds and enable only when it makes sense.
- (void) image2; // Ignored.
- (void) x2; // Ignored.
- (void) y2; // Ignored.
+ (void)image2; // Ignored.
+ (void)x2; // Ignored.
+ (void)y2; // Ignored.
return true;
}
-bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) {
+bool PointOnRightHalfPlane(const Vec2& a, const Vec2& b, double x, double y) {
Vec2 ba = b - a;
return ((Vec2(x, y) - b).transpose() * Vec2(-ba.y(), ba.x())) > 0;
}
@@ -1102,7 +1097,7 @@ bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) {
// y
//
// The implementation does up to four half-plane comparisons.
-bool PointInQuad(const double *xs, const double *ys, double x, double y) {
+bool PointInQuad(const double* xs, const double* ys, double x, double y) {
Vec2 a0(xs[0], ys[0]);
Vec2 a1(xs[1], ys[1]);
Vec2 a2(xs[2], ys[2]);
@@ -1116,24 +1111,27 @@ bool PointInQuad(const double *xs, const double *ys, double x, double y) {
// This makes it possible to map between Eigen float arrays and FloatImage
// without using comparisons.
-typedef Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> FloatArray;
+typedef Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
+ FloatArray;
// This creates a pattern in the frame of image2, from the pixel is image1,
// based on the initial guess represented by the two quads x1, y1, and x2, y2.
-template<typename Warp>
-void CreateBrutePattern(const double *x1, const double *y1,
- const double *x2, const double *y2,
- const FloatImage &image1,
- const FloatImage *image1_mask,
- FloatArray *pattern,
- FloatArray *mask,
- int *origin_x,
- int *origin_y) {
+template <typename Warp>
+void CreateBrutePattern(const double* x1,
+ const double* y1,
+ const double* x2,
+ const double* y2,
+ const FloatImage& image1,
+ const FloatImage* image1_mask,
+ FloatArray* pattern,
+ FloatArray* mask,
+ int* origin_x,
+ int* origin_y) {
// Get integer bounding box of quad2 in image2.
int min_x = static_cast<int>(floor(*std::min_element(x2, x2 + 4)));
int min_y = static_cast<int>(floor(*std::min_element(y2, y2 + 4)));
- int max_x = static_cast<int>(ceil (*std::max_element(x2, x2 + 4)));
- int max_y = static_cast<int>(ceil (*std::max_element(y2, y2 + 4)));
+ int max_x = static_cast<int>(ceil(*std::max_element(x2, x2 + 4)));
+ int max_y = static_cast<int>(ceil(*std::max_element(y2, y2 + 4)));
int w = max_x - min_x;
int h = max_y - min_y;
@@ -1154,9 +1152,8 @@ void CreateBrutePattern(const double *x1, const double *y1,
double dst_y = r;
double src_x;
double src_y;
- inverse_warp.Forward(inverse_warp.parameters,
- dst_x, dst_y,
- &src_x, &src_y);
+ inverse_warp.Forward(
+ inverse_warp.parameters, dst_x, dst_y, &src_x, &src_y);
if (PointInQuad(x1, y1, src_x, src_y)) {
(*pattern)(i, j) = SampleLinear(image1, src_y, src_x);
@@ -1191,24 +1188,32 @@ void CreateBrutePattern(const double *x1, const double *y1,
// pattern, when doing brute initialization. Unfortunately that implies a
// totally different warping interface, since access to more than a the source
// and current destination frame is necessary.
-template<typename Warp>
-bool BruteTranslationOnlyInitialize(const FloatImage &image1,
- const FloatImage *image1_mask,
- const FloatImage &image2,
+template <typename Warp>
+bool BruteTranslationOnlyInitialize(const FloatImage& image1,
+ const FloatImage* image1_mask,
+ const FloatImage& image2,
const int num_extra_points,
const bool use_normalized_intensities,
- const double *x1, const double *y1,
- double *x2, double *y2) {
+ const double* x1,
+ const double* y1,
+ double* x2,
+ double* y2) {
// Create the pattern to match in the space of image2, assuming our inital
// guess isn't too far from the template in image1. If there is no image1
// mask, then the resulting mask is binary.
FloatArray pattern;
FloatArray mask;
int origin_x = -1, origin_y = -1;
- CreateBrutePattern<Warp>(x1, y1, x2, y2,
- image1, image1_mask,
- &pattern, &mask,
- &origin_x, &origin_y);
+ CreateBrutePattern<Warp>(x1,
+ y1,
+ x2,
+ y2,
+ image1,
+ image1_mask,
+ &pattern,
+ &mask,
+ &origin_x,
+ &origin_y);
// For normalization, premultiply the pattern by the inverse pattern mean.
double mask_sum = 1.0;
@@ -1251,8 +1256,10 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1,
// instead, reducing the mean calculation to an O(1) operation.
double inverse_search_mean =
mask_sum / ((mask * search.block(r, c, h, w)).sum());
- sad = (mask * (pattern - (search.block(r, c, h, w) *
- inverse_search_mean))).abs().sum();
+ sad = (mask *
+ (pattern - (search.block(r, c, h, w) * inverse_search_mean)))
+ .abs()
+ .sum();
} else {
sad = (mask * (pattern - search.block(r, c, h, w))).abs().sum();
}
@@ -1274,9 +1281,8 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1,
<< "best_c: " << best_c << ", best_r: " << best_r << ", "
<< "origin_x: " << origin_x << ", origin_y: " << origin_y << ", "
<< "dc: " << (best_c - origin_x) << ", "
- << "dr: " << (best_r - origin_y)
- << ", tried " << ((image2.Height() - h) * (image2.Width() - w))
- << " shifts.";
+ << "dr: " << (best_r - origin_y) << ", tried "
+ << ((image2.Height() - h) * (image2.Width() - w)) << " shifts.";
// Apply the shift.
for (int i = 0; i < 4 + num_extra_points; ++i) {
@@ -1286,8 +1292,10 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1,
return true;
}
-void CopyQuad(double *src_x, double *src_y,
- double *dst_x, double *dst_y,
+void CopyQuad(double* src_x,
+ double* src_y,
+ double* dst_x,
+ double* dst_y,
int num_extra_points) {
for (int i = 0; i < 4 + num_extra_points; ++i) {
dst_x[i] = src_x[i];
@@ -1297,16 +1305,18 @@ void CopyQuad(double *src_x, double *src_y,
} // namespace
-template<typename Warp>
-void TemplatedTrackRegion(const FloatImage &image1,
- const FloatImage &image2,
- const double *x1, const double *y1,
- const TrackRegionOptions &options,
- double *x2, double *y2,
- TrackRegionResult *result) {
+template <typename Warp>
+void TemplatedTrackRegion(const FloatImage& image1,
+ const FloatImage& image2,
+ const double* x1,
+ const double* y1,
+ const TrackRegionOptions& options,
+ double* x2,
+ double* y2,
+ TrackRegionResult* result) {
for (int i = 0; i < 4 + options.num_extra_points; ++i) {
- LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess ("
- << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", "
+ LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess (" << x2[i]
+ << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", "
<< (y2[i] - y1[i]) << ").";
}
@@ -1322,9 +1332,14 @@ void TemplatedTrackRegion(const FloatImage &image1,
double y2_first_try[5];
CopyQuad(x2, y2, x2_first_try, y2_first_try, options.num_extra_points);
- TemplatedTrackRegion<Warp>(image1, image2,
- x1, y1, modified_options,
- x2_first_try, y2_first_try, result);
+ TemplatedTrackRegion<Warp>(image1,
+ image2,
+ x1,
+ y1,
+ modified_options,
+ x2_first_try,
+ y2_first_try,
+ result);
// Of the things that can happen in the first pass, don't try the brute
// pass (and second attempt) if the error is one of the terminations below.
@@ -1368,22 +1383,25 @@ void TemplatedTrackRegion(const FloatImage &image1,
// Prepare the image and gradient.
Array3Df image_and_gradient1;
Array3Df image_and_gradient2;
- BlurredImageAndDerivativesChannels(image1, options.sigma,
- &image_and_gradient1);
- BlurredImageAndDerivativesChannels(image2, options.sigma,
- &image_and_gradient2);
+ BlurredImageAndDerivativesChannels(
+ image1, options.sigma, &image_and_gradient1);
+ BlurredImageAndDerivativesChannels(
+ image2, options.sigma, &image_and_gradient2);
// Possibly do a brute-force translation-only initialization.
if (SearchAreaTooBigForDescent(image2, x2, y2) &&
options.use_brute_initialization) {
LG << "Running brute initialization...";
- bool found_any_alignment = BruteTranslationOnlyInitialize<Warp>(
- image_and_gradient1,
- options.image1_mask,
- image2,
- options.num_extra_points,
- options.use_normalized_intensities,
- x1, y1, x2, y2);
+ bool found_any_alignment =
+ BruteTranslationOnlyInitialize<Warp>(image_and_gradient1,
+ options.image1_mask,
+ image2,
+ options.num_extra_points,
+ options.use_normalized_intensities,
+ x1,
+ y1,
+ x2,
+ y2);
if (!found_any_alignment) {
LG << "Brute failed to find an alignment; pattern too small. "
<< "Failing entire track operation.";
@@ -1391,9 +1409,9 @@ void TemplatedTrackRegion(const FloatImage &image1,
return;
}
for (int i = 0; i < 4; ++i) {
- LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute ("
- << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i])
- << ", " << (y2[i] - y1[i]) << ").";
+ LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" << x2[i]
+ << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", "
+ << (y2[i] - y1[i]) << ").";
}
}
@@ -1408,14 +1426,13 @@ void TemplatedTrackRegion(const FloatImage &image1,
PickSampling(x1, y1, x2, y2, &num_samples_x, &num_samples_y);
// Compute the warp from rectangular coordinates.
- Mat3 canonical_homography = ComputeCanonicalHomography(x1, y1,
- num_samples_x,
- num_samples_y);
+ Mat3 canonical_homography =
+ ComputeCanonicalHomography(x1, y1, num_samples_x, num_samples_y);
ceres::Problem problem;
// Construct the warp cost function. AutoDiffCostFunction takes ownership.
- PixelDifferenceCostFunctor<Warp> *pixel_difference_cost_function =
+ PixelDifferenceCostFunctor<Warp>* pixel_difference_cost_function =
new PixelDifferenceCostFunctor<Warp>(options,
image_and_gradient1,
image_and_gradient2,
@@ -1424,28 +1441,24 @@ void TemplatedTrackRegion(const FloatImage &image1,
num_samples_y,
warp);
problem.AddResidualBlock(
- new ceres::AutoDiffCostFunction<
- PixelDifferenceCostFunctor<Warp>,
- ceres::DYNAMIC,
- Warp::NUM_PARAMETERS>(pixel_difference_cost_function,
- num_samples_x * num_samples_y),
- NULL,
- warp.parameters);
+ new ceres::AutoDiffCostFunction<PixelDifferenceCostFunctor<Warp>,
+ ceres::DYNAMIC,
+ Warp::NUM_PARAMETERS>(
+ pixel_difference_cost_function, num_samples_x * num_samples_y),
+ NULL,
+ warp.parameters);
// Construct the regularizing cost function
if (options.regularization_coefficient != 0.0) {
- WarpRegularizingCostFunctor<Warp> *regularizing_warp_cost_function =
- new WarpRegularizingCostFunctor<Warp>(options,
- x1, y2,
- x2_original,
- y2_original,
- warp);
+ WarpRegularizingCostFunctor<Warp>* regularizing_warp_cost_function =
+ new WarpRegularizingCostFunctor<Warp>(
+ options, x1, y2, x2_original, y2_original, warp);
problem.AddResidualBlock(
- new ceres::AutoDiffCostFunction<
- WarpRegularizingCostFunctor<Warp>,
- 8 /* num_residuals */,
- Warp::NUM_PARAMETERS>(regularizing_warp_cost_function),
+ new ceres::AutoDiffCostFunction<WarpRegularizingCostFunctor<Warp>,
+ 8 /* num_residuals */,
+ Warp::NUM_PARAMETERS>(
+ regularizing_warp_cost_function),
NULL,
warp.parameters);
}
@@ -1488,10 +1501,10 @@ void TemplatedTrackRegion(const FloatImage &image1,
return;
}
-#define HANDLE_TERMINATION(termination_enum) \
- if (summary.termination_type == ceres::termination_enum) { \
- result->termination = TrackRegionResult::termination_enum; \
- return; \
+#define HANDLE_TERMINATION(termination_enum) \
+ if (summary.termination_type == ceres::termination_enum) { \
+ result->termination = TrackRegionResult::termination_enum; \
+ return; \
}
// Avoid computing correlation for tracking failures.
@@ -1499,8 +1512,9 @@ void TemplatedTrackRegion(const FloatImage &image1,
// Otherwise, run a final correlation check.
if (options.minimum_correlation > 0.0) {
- result->correlation = pixel_difference_cost_function->
- PearsonProductMomentCorrelationCoefficient(warp.parameters);
+ result->correlation =
+ pixel_difference_cost_function
+ ->PearsonProductMomentCorrelationCoefficient(warp.parameters);
if (result->correlation < options.minimum_correlation) {
LG << "Failing with insufficient correlation.";
result->termination = TrackRegionResult::INSUFFICIENT_CORRELATION;
@@ -1523,36 +1537,39 @@ void TemplatedTrackRegion(const FloatImage &image1,
#undef HANDLE_TERMINATION
};
-void TrackRegion(const FloatImage &image1,
- const FloatImage &image2,
- const double *x1, const double *y1,
- const TrackRegionOptions &options,
- double *x2, double *y2,
- TrackRegionResult *result) {
+void TrackRegion(const FloatImage& image1,
+ const FloatImage& image2,
+ const double* x1,
+ const double* y1,
+ const TrackRegionOptions& options,
+ double* x2,
+ double* y2,
+ TrackRegionResult* result) {
// Enum is necessary due to templated nature of autodiff.
-#define HANDLE_MODE(mode_enum, mode_type) \
- if (options.mode == TrackRegionOptions::mode_enum) { \
- TemplatedTrackRegion<mode_type>(image1, image2, \
- x1, y1, \
- options, \
- x2, y2, \
- result); \
- return; \
+#define HANDLE_MODE(mode_enum, mode_type) \
+ if (options.mode == TrackRegionOptions::mode_enum) { \
+ TemplatedTrackRegion<mode_type>( \
+ image1, image2, x1, y1, options, x2, y2, result); \
+ return; \
}
- HANDLE_MODE(TRANSLATION, TranslationWarp);
- HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp);
- HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp);
+ HANDLE_MODE(TRANSLATION, TranslationWarp);
+ HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp);
+ HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp);
HANDLE_MODE(TRANSLATION_ROTATION_SCALE, TranslationRotationScaleWarp);
- HANDLE_MODE(AFFINE, AffineWarp);
- HANDLE_MODE(HOMOGRAPHY, HomographyWarp);
+ HANDLE_MODE(AFFINE, AffineWarp);
+ HANDLE_MODE(HOMOGRAPHY, HomographyWarp);
#undef HANDLE_MODE
}
-bool SamplePlanarPatch(const FloatImage &image,
- const double *xs, const double *ys,
- int num_samples_x, int num_samples_y,
- FloatImage *mask, FloatImage *patch,
- double *warped_position_x, double *warped_position_y) {
+bool SamplePlanarPatch(const FloatImage& image,
+ const double* xs,
+ const double* ys,
+ int num_samples_x,
+ int num_samples_y,
+ FloatImage* mask,
+ FloatImage* patch,
+ double* warped_position_x,
+ double* warped_position_y) {
// Bail early if the points are outside the image.
if (!AllInBounds(image, xs, ys)) {
LG << "Can't sample patch: out of bounds.";
@@ -1563,9 +1580,8 @@ bool SamplePlanarPatch(const FloatImage &image,
patch->Resize(num_samples_y, num_samples_x, image.Depth());
// Compute the warp from rectangular coordinates.
- Mat3 canonical_homography = ComputeCanonicalHomography(xs, ys,
- num_samples_x,
- num_samples_y);
+ Mat3 canonical_homography =
+ ComputeCanonicalHomography(xs, ys, num_samples_x, num_samples_y);
// Walk over the coordinates in the canonical space, sampling from the image
// in the original space and copying the result into the patch.
@@ -1573,12 +1589,11 @@ bool SamplePlanarPatch(const FloatImage &image,
for (int c = 0; c < num_samples_x; ++c) {
Vec3 image_position = canonical_homography * Vec3(c, r, 1);
image_position /= image_position(2);
- SampleLinear(image, image_position(1),
- image_position(0),
- &(*patch)(r, c, 0));
+ SampleLinear(
+ image, image_position(1), image_position(0), &(*patch)(r, c, 0));
if (mask) {
- float mask_value = SampleLinear(*mask, image_position(1),
- image_position(0), 0);
+ float mask_value =
+ SampleLinear(*mask, image_position(1), image_position(0), 0);
for (int d = 0; d < image.Depth(); d++)
(*patch)(r, c, d) *= mask_value;
diff --git a/intern/libmv/libmv/tracking/track_region.h b/intern/libmv/libmv/tracking/track_region.h
index 61dce22bcb8..61d81413a29 100644
--- a/intern/libmv/libmv/tracking/track_region.h
+++ b/intern/libmv/libmv/tracking/track_region.h
@@ -19,6 +19,7 @@
// IN THE SOFTWARE.
#ifndef LIBMV_TRACKING_TRACK_REGION_H_
+#define LIBMV_TRACKING_TRACK_REGION_H_
#include "libmv/image/image.h"
#include "libmv/image/sample.h"
@@ -29,6 +30,12 @@ namespace libmv {
struct TrackRegionOptions {
TrackRegionOptions();
+ enum Direction {
+ FORWARD,
+ BACKWARD,
+ };
+ Direction direction;
+
enum Mode {
TRANSLATION,
TRANSLATION_ROTATION,
@@ -40,7 +47,7 @@ struct TrackRegionOptions {
Mode mode;
// Minimum normalized cross-correlation necessary between the final tracked
- // positoin of the patch on the destination image and the reference patch
+ // position of the patch on the destination image and the reference patch
// needed to declare tracking success. If the minimum correlation is not met,
// then TrackResult::termination is INSUFFICIENT_CORRELATION.
double minimum_correlation;
@@ -54,7 +61,7 @@ struct TrackRegionOptions {
// If true, apply a brute-force translation-only search before attempting the
// full search. This is not enabled if the destination image ("image2") is
- // too small; in that case eithen the basin of attraction is close enough
+ // too small; in that case either the basin of attraction is close enough
// that the nearby minima is correct, or the search area is too small.
bool use_brute_initialization;
@@ -107,7 +114,7 @@ struct TrackRegionOptions {
// If non-null, this is used as the pattern mask. It should match the size of
// image1, even though only values inside the image1 quad are examined. The
// values must be in the range 0.0 to 0.1.
- FloatImage *image1_mask;
+ FloatImage* image1_mask;
};
struct TrackRegionResult {
@@ -128,8 +135,7 @@ struct TrackRegionResult {
Termination termination;
bool is_usable() {
- return termination == CONVERGENCE ||
- termination == NO_CONVERGENCE;
+ return termination == CONVERGENCE || termination == NO_CONVERGENCE;
}
int num_iterations;
@@ -140,12 +146,14 @@ struct TrackRegionResult {
};
// Always needs 4 correspondences.
-void TrackRegion(const FloatImage &image1,
- const FloatImage &image2,
- const double *x1, const double *y1,
- const TrackRegionOptions &options,
- double *x2, double *y2,
- TrackRegionResult *result);
+void TrackRegion(const FloatImage& image1,
+ const FloatImage& image2,
+ const double* x1,
+ const double* y1,
+ const TrackRegionOptions& options,
+ double* x2,
+ double* y2,
+ TrackRegionResult* result);
// Sample a "canonical" version of the passed planar patch, using bilinear
// sampling. The passed corners must be within the image, and have at least two
@@ -156,11 +164,15 @@ void TrackRegion(const FloatImage &image1,
// the size of image.
// Warped coordinates of marker's position would be returned in
// warped_position_x and warped_position_y
-bool SamplePlanarPatch(const FloatImage &image,
- const double *xs, const double *ys,
- int num_samples_x, int num_samples_y,
- FloatImage *mask, FloatImage *patch,
- double *warped_position_x, double *warped_position_y);
+bool SamplePlanarPatch(const FloatImage& image,
+ const double* xs,
+ const double* ys,
+ int num_samples_x,
+ int num_samples_y,
+ FloatImage* mask,
+ FloatImage* patch,
+ double* warped_position_x,
+ double* warped_position_y);
} // namespace libmv
diff --git a/intern/libmv/libmv/tracking/trklt_region_tracker.cc b/intern/libmv/libmv/tracking/trklt_region_tracker.cc
index 05ef3d1d272..7ffa7555467 100644
--- a/intern/libmv/libmv/tracking/trklt_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/trklt_region_tracker.cc
@@ -20,27 +20,29 @@
#include "libmv/tracking/trklt_region_tracker.h"
-#include "libmv/logging/logging.h"
-#include "libmv/numeric/numeric.h"
-#include "libmv/image/image.h"
#include "libmv/image/convolve.h"
+#include "libmv/image/image.h"
#include "libmv/image/sample.h"
+#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
namespace libmv {
// TODO(keir): Switch this to use the smarter LM loop like in ESM.
// Computes U and e from the Ud = e equation (number 14) from the paper.
-static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
- const Array3Df &image_and_gradient2,
- double x1, double y1,
- double x2, double y2,
+static void ComputeTrackingEquation(const Array3Df& image_and_gradient1,
+ const Array3Df& image_and_gradient2,
+ double x1,
+ double y1,
+ double x2,
+ double y2,
int half_width,
double lambda,
- Mat2f *U,
- Vec2f *e) {
+ Mat2f* U,
+ Vec2f* e) {
Mat2f A, B, C, D;
- A = B = C = D = Mat2f::Zero();
+ A = B = C = D = Mat2f::Zero();
Vec2f R, S, V, W;
R = S = V = W = Vec2f::Zero();
@@ -57,9 +59,9 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
Vec2f gI, gJ;
gI << SampleLinear(image_and_gradient1, yy1, xx1, 1),
- SampleLinear(image_and_gradient1, yy1, xx1, 2);
+ SampleLinear(image_and_gradient1, yy1, xx1, 2);
gJ << SampleLinear(image_and_gradient2, yy2, xx2, 1),
- SampleLinear(image_and_gradient2, yy2, xx2, 2);
+ SampleLinear(image_and_gradient2, yy2, xx2, 2);
// Equation 15 from the paper.
A += gI * gI.transpose();
@@ -77,26 +79,25 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
Mat2f Di = B.transpose().inverse();
// Equation 14 from the paper.
- *U = A*Di*C + lambda*Di*C - 0.5*B;
- *e = (A + lambda*Mat2f::Identity())*Di*(V - W) + 0.5*(S - R);
+ *U = A * Di * C + lambda * Di * C - 0.5 * B;
+ *e = (A + lambda * Mat2f::Identity()) * Di * (V - W) + 0.5 * (S - R);
}
-static bool RegionIsInBounds(const FloatImage &image1,
- double x, double y,
- int half_window_size) {
+static bool RegionIsInBounds(const FloatImage& image1,
+ double x,
+ double y,
+ int half_window_size) {
// Check the minimum coordinates.
int min_x = floor(x) - half_window_size - 1;
int min_y = floor(y) - half_window_size - 1;
- if (min_x < 0.0 ||
- min_y < 0.0) {
+ if (min_x < 0.0 || min_y < 0.0) {
return false;
}
// Check the maximum coordinates.
int max_x = ceil(x) + half_window_size + 1;
int max_y = ceil(y) + half_window_size + 1;
- if (max_x > image1.cols() ||
- max_y > image1.rows()) {
+ if (max_x > image1.cols() || max_y > image1.rows()) {
return false;
}
@@ -104,10 +105,12 @@ static bool RegionIsInBounds(const FloatImage &image1,
return true;
}
-bool TrkltRegionTracker::Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const {
+bool TrkltRegionTracker::Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const {
if (!RegionIsInBounds(image1, x1, y1, half_window_size)) {
LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1
<< ", hw=" << half_window_size << ".";
@@ -134,11 +137,14 @@ bool TrkltRegionTracker::Track(const FloatImage &image1,
Vec2f e;
ComputeTrackingEquation(image_and_gradient1,
image_and_gradient2,
- x1, y1,
- *x2, *y2,
+ x1,
+ y1,
+ *x2,
+ *y2,
half_window_size,
lambda,
- &U, &e);
+ &U,
+ &e);
// Solve the linear system for the best update to x2 and y2.
d = U.lu().solve(e);
@@ -161,7 +167,6 @@ bool TrkltRegionTracker::Track(const FloatImage &image1,
LG << "x=" << *x2 << ", y=" << *y2 << ", dx=" << d[0] << ", dy=" << d[1]
<< ", det=" << determinant;
-
// If the update is small, then we probably found the target.
if (d.squaredNorm() < min_update_squared_distance) {
LG << "Successful track in " << i << " iterations.";
diff --git a/intern/libmv/libmv/tracking/trklt_region_tracker.h b/intern/libmv/libmv/tracking/trklt_region_tracker.h
index 26d0621aa02..a9cf5580f61 100644
--- a/intern/libmv/libmv/tracking/trklt_region_tracker.h
+++ b/intern/libmv/libmv/tracking/trklt_region_tracker.h
@@ -46,10 +46,12 @@ struct TrkltRegionTracker : public RegionTracker {
virtual ~TrkltRegionTracker() {}
// Tracker interface.
- virtual bool Track(const FloatImage &image1,
- const FloatImage &image2,
- double x1, double y1,
- double *x2, double *y2) const;
+ virtual bool Track(const FloatImage& image1,
+ const FloatImage& image2,
+ double x1,
+ double y1,
+ double* x2,
+ double* y2) const;
// No point in creating getters or setters.
int half_window_size;
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index c4d7a0c4fe9..146d5d1a5a7 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -326,7 +326,8 @@ void OCIOImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config_, float xyz_to_rg
{
ConstConfigRcPtr config = (*(ConstConfigRcPtr *)config_);
- /* Default to ITU-BT.709 in case no appropriate transform found. */
+ /* Default to ITU-BT.709 in case no appropriate transform found.
+ * Note XYZ is defined here as having a D65 white point. */
memcpy(xyz_to_rgb, OCIO_XYZ_TO_LINEAR_SRGB, sizeof(OCIO_XYZ_TO_LINEAR_SRGB));
/* Get from OpenColorO config if it has the required roles. */
@@ -336,12 +337,15 @@ void OCIOImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config_, float xyz_to_rg
if (config->hasRole("aces_interchange")) {
/* Standard OpenColorIO role, defined as ACES2065-1. */
- const float xyz_to_aces[3][3] = {{1.0498110175f, -0.4959030231f, 0.0f},
- {0.0f, 1.3733130458f, 0.0f},
- {-0.0000974845f, 0.0982400361f, 0.9912520182f}};
+ const float xyz_E_to_aces[3][3] = {{1.0498110175f, -0.4959030231f, 0.0f},
+ {0.0f, 1.3733130458f, 0.0f},
+ {-0.0000974845f, 0.0982400361f, 0.9912520182f}};
+ const float xyz_D65_to_E[3][3] = {
+ {1.0521111f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.9184170f}};
+
float aces_to_rgb[3][3];
if (to_scene_linear_matrix(config, "aces_interchange", aces_to_rgb)) {
- mul_m3_m3m3(xyz_to_rgb, aces_to_rgb, xyz_to_aces);
+ mul_m3_series(xyz_to_rgb, aces_to_rgb, xyz_E_to_aces, xyz_D65_to_E);
}
}
else if (config->hasRole("XYZ")) {
diff --git a/intern/utfconv/utfconv.h b/intern/utfconv/utfconv.h
index 36dff288966..b4addd72c75 100644
--- a/intern/utfconv/utfconv.h
+++ b/intern/utfconv/utfconv.h
@@ -32,32 +32,36 @@ extern "C" {
/**
* Counts how many bytes is required for future utf-8 string using utf-16
* \param string16: pointer to working utf-16 string
- * \return How many bytes must be allocated includeng NULL.
+ * \return How many bytes must be allocated including NULL.
*/
size_t count_utf_8_from_16(const wchar_t *string16);
/**
* Counts how many wchar_t (two byte) is required for future utf-16 string using utf-8
* \param string8: pointer to working utf-8 string
- * \return How many bytes must be allocated includeng NULL.
+ * \return How many bytes must be allocated including NULL.
*/
size_t count_utf_16_from_8(const char *string8);
-/**
+/*
* conv_utf_*** errors
*/
-#define UTF_ERROR_NULL_IN (1 << 0) /* Error occures when requered parameter is missing*/
-#define UTF_ERROR_ILLCHAR (1 << 1) /* Error if character is in illigal UTF rage*/
-#define UTF_ERROR_SMALL \
- (1 << 2) /* Passed size is to small. It gives legal string with character missing at the end */
-#define UTF_ERROR_ILLSEQ (1 << 3) /* Error if sequence is broken and doesn't finish*/
+
+/** Error occurs when required parameter is missing. */
+#define UTF_ERROR_NULL_IN (1 << 0)
+/** Error if character is in illegal UTF range. */
+#define UTF_ERROR_ILLCHAR (1 << 1)
+/** Passed size is to small. It gives legal string with character missing at the end. */
+#define UTF_ERROR_SMALL (1 << 2)
+/** Error if sequence is broken and doesn't finish. */
+#define UTF_ERROR_ILLSEQ (1 << 3)
/**
* Converts utf-16 string to allocated utf-8 string
* \param in16: utf-16 string to convert
* \param out8: utf-8 string to string the conversion
* \param size8: the allocated size in bytes of out8
- * \return Returns any errors occured during conversion. See the block above,
+ * \return Returns any errors occurred during conversion. See the block above,
*/
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8);
@@ -66,7 +70,7 @@ int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8);
* \param in8: utf-8 string to convert
* \param out16: utf-16 string to string the conversion
* \param size16: the allocated size in wchar_t (two byte) of out16
- * \return Returns any errors occured during conversion. See the block above,
+ * \return Returns any errors occurred during conversion. See the block above,
*/
int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16);
diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio
index 156ca960e88..bb9fd27fb84 100644
--- a/release/datafiles/colormanagement/config.ocio
+++ b/release/datafiles/colormanagement/config.ocio
@@ -100,6 +100,7 @@ colorspaces:
from_reference: !<GroupTransform>
children:
- !<FileTransform> {src: srgb_to_xyz.spimtx, interpolation: linear}
+ - !<FileTransform> {src: xyz_D65_to_E.spimtx, interpolation: linear}
- !<FileTransform> {src: xyz_to_aces.spimtx, interpolation: linear}
- !<ColorSpace>
diff --git a/release/datafiles/colormanagement/luts/xyz_D65_to_E.spimtx b/release/datafiles/colormanagement/luts/xyz_D65_to_E.spimtx
new file mode 100644
index 00000000000..3670b94c9fe
--- /dev/null
+++ b/release/datafiles/colormanagement/luts/xyz_D65_to_E.spimtx
@@ -0,0 +1,3 @@
+1.0521111 0.0000000 0.0000000 0
+0.0000000 1.0000000 0.0000000 0
+0.0000000 0.0000000 0.9184170 0
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject aafea2abb18bb42e7d31a6926b2caba90f4e031
+Subproject ef74c1b861a1b05c2483a2c045a638070416749
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index 6383d7dfcca..6220edce28f 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -226,6 +226,7 @@ const UserDef U_default = {
.sequencer_disk_cache_compression = 0,
.sequencer_disk_cache_size_limit = 100,
.sequencer_disk_cache_flag = 0,
+ .sequencer_proxy_setup = USER_SEQ_PROXY_SETUP_AUTOMATIC,
.collection_instance_empty_size = 1.0f,
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 0477b0c9f23..5b34515d080 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -1009,6 +1009,38 @@ const bTheme U_theme_default = {
.facedot_size = 4,
.gp_vertex_size = 3,
},
+ .space_spreadsheet = {
+ .back = RGBA(0x28282800),
+ .title = RGBA(0xffffffff),
+ .text = RGBA(0xc3c3c3ff),
+ .text_hi = RGBA(0xffffffff),
+ .header = RGBA(0x454545ff),
+ .header_text = RGBA(0xeeeeeeff),
+ .header_text_hi = RGBA(0xffffffff),
+ .tab_active = RGBA(0x4b4b4bff),
+ .tab_inactive = RGBA(0x2b2b2bff),
+ .tab_back = RGBA(0x232323ff),
+ .tab_outline = RGBA(0x232323ff),
+ .button = RGBA(0x424242ff),
+ .button_title = RGBA(0xffffffff),
+ .button_text = RGBA(0xe5e5e5ff),
+ .button_text_hi = RGBA(0xffffffff),
+ .panelcolors = {
+ .header = RGBA(0x424242cc),
+ .back = RGBA(0x333333b3),
+ .sub_back = RGBA(0x0000003e),
+ },
+ .active = RGBA(0x3b5689ff),
+ .vertex_size = 3,
+ .outline_width = 1,
+ .facedot_size = 4,
+ .match = RGBA(0x337f334c),
+ .selected_highlight = RGBA(0x223a5bff),
+ .selected_object = RGBA(0xe96a00ff),
+ .active_object = RGBA(0xffaf29ff),
+ .edited_object = RGBA(0x00806266),
+ .row_alternate = RGBA(0xffffff07),
+ },
.tarm = {
{
.solid = RGBA(0x9a0000ff),
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 24e756c0da89bdbf88dc22163ae3b7ef4f1fbb7
+Subproject 6dfba915743b67aff99ddcc19c0807d339a87c9
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject a140f066ac99e1860af38080f008507029a3470
+Subproject ef6ef414d22c2578fad99327743b925ab640a99
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 180f9f0a01c..3355e9075a0 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -22,8 +22,6 @@
# XXX: This script is meant to be used from inside Blender!
# You should not directly use this script, rather use update_msg.py!
-import collections
-import copy
import datetime
import os
import re
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index fd4488ecd73..b17c9eeebc5 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -21,12 +21,9 @@
# Some misc utilities...
import collections
-import copy
-import hashlib
import os
import re
import struct
-import sys
import tempfile
#import time
diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
index 2b6a56c5deb..8da1417c468 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
@@ -32,7 +32,6 @@
# \", %s, %x12, %.4f, etc.), protecting them from ugly (evil) fribidi,
# which seems completely unaware of such things (as unicode is...).
-import sys
import ctypes
import re
@@ -89,7 +88,7 @@ def protect_format_seq(msg):
PDF = "\u202C"
LRO = "\u202D"
RLO = "\u202E"
- uctrl = {LRE, RLE, PDF, LRO, RLO}
+ # uctrl = {LRE, RLE, PDF, LRO, RLO}
# Most likely incomplete, but seems to cover current needs.
format_codes = set("tslfd")
digits = set(".0123456789")
diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
index 6e3d04e7fa2..979b47f7a14 100644
--- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py
+++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
@@ -283,7 +283,8 @@ def do_previews(do_objects, do_collections, do_scenes, do_data_intern):
return cos
def preview_render_do(render_context, item_container, item_name, objects, offset_matrix=None):
- scene = bpy.data.scenes[render_context.scene, None]
+ # Unused.
+ # scene = bpy.data.scenes[render_context.scene, None]
if objects is not None:
camera = bpy.data.objects[render_context.camera, None]
light = bpy.data.objects[render_context.light, None] if render_context.light is not None else None
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 8afb09882fd..ddfd3d66e90 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -32,7 +32,6 @@ __all__ = (
import bpy
from bpy.props import (
- BoolProperty,
FloatVectorProperty,
EnumProperty,
)
@@ -50,7 +49,7 @@ def add_object_align_init(context, operator):
:rtype: :class:`mathutils.Matrix`
"""
- from mathutils import Matrix, Vector, Euler
+ from mathutils import Matrix, Vector
properties = operator.properties if operator is not None else None
space_data = context.space_data
@@ -113,7 +112,6 @@ def object_data_add(context, obdata, operator=None, name=None):
:return: the newly created object in the scene.
:rtype: :class:`bpy.types.Object`
"""
- scene = context.scene
layer = context.view_layer
layer_collection = context.layer_collection or layer.active_layer_collection
scene_collection = layer_collection.collection
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 5d89763f34b..ee9115b6643 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -19,7 +19,6 @@
# <pep8-80 compliant>
from _bpy import types as bpy_types
-import _bpy
StructRNA = bpy_types.bpy_struct
StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop
@@ -900,6 +899,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
layout = self.layout
import os
+ import re
import bpy.utils
layout = self.layout
@@ -920,7 +920,11 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
(filter_path(f)))
])
- files.sort()
+ # Perform a "natural sort", so 20 comes after 3 (for example).
+ files.sort(
+ key=lambda file_path:
+ tuple(int(t) if t.isdigit() else t for t in re.split("(\d+)", file_path[0].lower())),
+ )
col = layout.column(align=True)
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
index 5106010b555..9e1b921774d 100644
--- a/release/scripts/modules/console_python.py
+++ b/release/scripts/modules/console_python.py
@@ -229,8 +229,6 @@ execute.hooks = []
def autocomplete(context):
- _readline_bypass()
-
from console import intellisense
sc = context.space_data
@@ -358,14 +356,3 @@ def banner(context):
sc.prompt = PROMPT
return {'FINISHED'}
-
-
-# workaround for readline crashing, see: T43491
-def _readline_bypass():
- if "rlcompleter" in sys.modules or "readline" in sys.modules:
- return
-
- # prevent 'rlcompleter' from loading the real 'readline' module.
- sys.modules["readline"] = None
- import rlcompleter
- del sys.modules["readline"]
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 964eff0e572..3bcc709ab72 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -622,8 +622,8 @@ def BuildRNAInfo():
yield (rna_sub_type_name, rna_sub_struct)
i += 1
- for (rna_type_name, rna_struct) in _bpy_types_iterator():
- # if not rna_type_name.startswith('__'):
+ for (_rna_type_name, rna_struct) in _bpy_types_iterator():
+ # if not _rna_type_name.startswith('__'):
identifier = rna_struct.identifier
diff --git a/release/scripts/presets/framerate/120.py b/release/scripts/presets/framerate/120.py
new file mode 100644
index 00000000000..53328907d2b
--- /dev/null
+++ b/release/scripts/presets/framerate/120.py
@@ -0,0 +1,3 @@
+import bpy
+bpy.context.scene.render.fps = 120
+bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/framerate/240.py b/release/scripts/presets/framerate/240.py
new file mode 100644
index 00000000000..096af4e38ec
--- /dev/null
+++ b/release/scripts/presets/framerate/240.py
@@ -0,0 +1,3 @@
+import bpy
+bpy.context.scene.render.fps = 240
+bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/interface_theme/Blender_Light.xml b/release/scripts/presets/interface_theme/Blender_Light.xml
index 77908bb6bbf..9da075ad949 100644
--- a/release/scripts/presets/interface_theme/Blender_Light.xml
+++ b/release/scripts/presets/interface_theme/Blender_Light.xml
@@ -1316,6 +1316,42 @@
</space>
</ThemeStatusBar>
</statusbar>
+ <spreadsheet>
+ <ThemeSpreadsheet
+ row_alternate="#ffffff0f"
+ >
+ <space>
+ <ThemeSpaceGeneric
+ back="#999999"
+ title="#000000"
+ text="#000000"
+ text_hi="#ffffff"
+ header="#adadadff"
+ header_text="#000000"
+ header_text_hi="#ffffff"
+ button="#999999e6"
+ button_title="#1a1a1a"
+ button_text="#000000"
+ button_text_hi="#ffffff"
+ navigation_bar="#00000000"
+ execution_buts="#999999e6"
+ tab_active="#6697e6"
+ tab_inactive="#cccccc"
+ tab_back="#999999ff"
+ tab_outline="#999999"
+ >
+ <panelcolors>
+ <ThemePanelColors
+ header="#42424200"
+ back="#00000028"
+ sub_back="#00000024"
+ >
+ </ThemePanelColors>
+ </panelcolors>
+ </ThemeSpaceGeneric>
+ </space>
+ </ThemeSpreadsheet>
+ </spreadsheet>
<bone_color_sets>
<ThemeBoneColorSet
normal="#9a0000"
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 949cfcae2b1..feba4e3bd09 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -352,12 +352,12 @@ def _template_items_tool_select_actions(operator, *, type, value):
# This could have a more generic name, for now use for circle select.
-def _template_items_tool_select_actions_simple(operator, *, type, value, properties=[]):
+def _template_items_tool_select_actions_simple(operator, *, type, value, properties=()):
kmi_args = {"type": type, "value": value}
return [
# Don't define 'SET' here, take from the tool options.
(operator, kmi_args,
- {"properties": properties}),
+ {"properties": [*properties]}),
(operator, {**kmi_args, "shift": True},
{"properties": [*properties, ("mode", 'ADD')]}),
(operator, {**kmi_args, "ctrl": True},
@@ -368,7 +368,11 @@ def _template_items_tool_select_actions_simple(operator, *, type, value, propert
def _template_items_legacy_tools_from_numbers():
return [
("wm.tool_set_by_index",
- {"type": NUMBERS_1[i % 10], "value": 'PRESS', "shift": i >= 10},
+ {
+ "type": NUMBERS_1[i % 10],
+ "value": 'PRESS',
+ **({"shift": True} if i >= 10 else {}),
+ },
{"properties": [("index", i)]})
for i in range(20)
]
@@ -1840,6 +1844,7 @@ def km_node_editor(params):
("node.resize", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("node.add_reroute", {"type": 'EVT_TWEAK_L' if params.legacy else 'EVT_TWEAK_R', "value": 'ANY', "shift": True}, None),
("node.links_cut", {"type": 'EVT_TWEAK_L' if params.legacy else 'EVT_TWEAK_R', "value": 'ANY', "ctrl": True}, None),
+ ("node.links_mute", {"type": 'EVT_TWEAK_R', "value": 'ANY', "ctrl": True, "alt": True}, None),
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("node.backimage_move", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "alt": True}, None),
("node.backimage_zoom", {"type": 'V', "value": 'PRESS', "repeat": True},
@@ -2011,7 +2016,6 @@ def km_file_browser_main(params):
# operator (i.e. in regular editor mode).
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("open", True), ("deselect_all", not params.legacy)]}),
- ("file.refresh", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("open", False), ("deselect_all", not params.legacy)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
@@ -2053,6 +2057,7 @@ def km_file_browser_main(params):
{"properties": [("mode", 'SUB')]}),
("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
+ ("file.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
])
return keymap
@@ -2728,7 +2733,7 @@ def km_console(_params):
("console.delete", {"type": 'BACK_SPACE', "value": 'PRESS', "repeat": True},
{"properties": [("type", 'PREVIOUS_CHARACTER')]}),
("console.delete", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True, "repeat": True},
- {"properties": [("type", 'PREVIOUS_CHARACTER')], "repeat": True}),
+ {"properties": [("type", 'PREVIOUS_CHARACTER')]}),
("console.delete", {"type": 'DEL', "value": 'PRESS', "ctrl": True, "repeat": True},
{"properties": [("type", 'NEXT_WORD')]}),
("console.delete", {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True, "repeat": True},
@@ -2900,7 +2905,9 @@ def km_clip_editor(params):
])
if not params.legacy:
- op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
+ items.extend([
+ op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
+ ])
else:
items.extend([
# Old pivot.
@@ -3065,7 +3072,7 @@ def km_frames(params):
return keymap
-def km_animation(params):
+def km_animation(_params):
items = []
keymap = (
"Animation",
@@ -3344,7 +3351,7 @@ def km_grease_pencil_stroke_edit_mode(params):
return keymap
-def km_grease_pencil_stroke_curve_edit_mode(params):
+def km_grease_pencil_stroke_curve_edit_mode(_params):
items = []
keymap = (
"Grease Pencil Stroke Curve Edit Mode",
@@ -3479,7 +3486,7 @@ def km_grease_pencil_stroke_paint_erase(params):
return keymap
-def km_grease_pencil_stroke_paint_fill(params):
+def km_grease_pencil_stroke_paint_fill(_params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Fill)",
@@ -3504,7 +3511,7 @@ def km_grease_pencil_stroke_paint_fill(params):
return keymap
-def km_grease_pencil_stroke_paint_tint(params):
+def km_grease_pencil_stroke_paint_tint(_params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Tint)",
@@ -3831,7 +3838,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
return keymap
-def km_grease_pencil_stroke_vertex_draw(params):
+def km_grease_pencil_stroke_vertex_draw(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Draw)",
@@ -3856,7 +3863,7 @@ def km_grease_pencil_stroke_vertex_draw(params):
return keymap
-def km_grease_pencil_stroke_vertex_blur(params):
+def km_grease_pencil_stroke_vertex_blur(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Blur)",
@@ -3879,7 +3886,7 @@ def km_grease_pencil_stroke_vertex_blur(params):
return keymap
-def km_grease_pencil_stroke_vertex_average(params):
+def km_grease_pencil_stroke_vertex_average(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Average)",
@@ -3904,7 +3911,7 @@ def km_grease_pencil_stroke_vertex_average(params):
return keymap
-def km_grease_pencil_stroke_vertex_smear(params):
+def km_grease_pencil_stroke_vertex_smear(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Smear)",
@@ -3927,7 +3934,7 @@ def km_grease_pencil_stroke_vertex_smear(params):
return keymap
-def km_grease_pencil_stroke_vertex_replace(params):
+def km_grease_pencil_stroke_vertex_replace(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Replace)",
@@ -4509,6 +4516,7 @@ def km_sculpt(params):
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("sculpt.dyntopo_detail_size_edit", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True, "alt": True}, None),
# Remesh
("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("object.voxel_size_edit", {"type": 'R', "value": 'PRESS', "shift": True}, None),
@@ -5586,28 +5594,26 @@ def km_sculpt_expand_modal(_params):
("CANCEL", {"type": 'ESC', "value": 'PRESS', "any": True}, None),
("CANCEL", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}, None),
("CONFIRM", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
- ("INVERT", {"type": 'F', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("PRESERVE", {"type": 'E', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("GRADIENT", {"type": 'G', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("RECURSION_STEP_GEODESIC", {"type": 'R', "value": 'PRESS', "repeat" : False}, None),
- ("RECURSION_STEP_TOPOLOGY", {"type": 'R', "value": 'PRESS', "alt" : True ,"any": True, "repeat" : False}, None),
- ("MOVE_TOGGLE", {"type": 'SPACE', "value": 'ANY', "any": True, "repeat" : False}, None),
- ("FALLOFF_GEODESICS", {"type": 'ONE', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("FALLOFF_TOPOLOGY", {"type": 'TWO', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("FALLOFF_TOPOLOGY_DIAGONALS", {"type": 'THREE', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("FALLOFF_SPHERICAL", {"type": 'FOUR', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("SNAP_TOGGLE", {"type": 'LEFT_CTRL', "value": 'ANY', "repeat" : False}, None),
- ("LOOP_COUNT_INCREASE", {"type": 'W', "value": 'PRESS', "any": True, "repeat" : True}, None),
- ("LOOP_COUNT_DECREASE", {"type": 'Q', "value": 'PRESS', "any": True, "repeat" : True}, None),
- ("BRUSH_GRADIENT_TOGGLE", {"type": 'B', "value": 'PRESS', "any": True, "repeat" : False}, None),
- ("TEXTURE_DISTORTION_INCREASE", {"type": 'Y', "value": 'PRESS', "any": False, "repeat" : True}, None),
- ("TEXTURE_DISTORTION_DECREASE", {"type": 'T', "value": 'PRESS', "any": False, "repeat" : True}, None),
+ ("INVERT", {"type": 'F', "value": 'PRESS', "any": True}, None),
+ ("PRESERVE", {"type": 'E', "value": 'PRESS', "any": True}, None),
+ ("GRADIENT", {"type": 'G', "value": 'PRESS', "any": True}, None),
+ ("RECURSION_STEP_GEODESIC", {"type": 'R', "value": 'PRESS'}, None),
+ ("RECURSION_STEP_TOPOLOGY", {"type": 'R', "value": 'PRESS', "alt": True}, None),
+ ("MOVE_TOGGLE", {"type": 'SPACE', "value": 'ANY', "any": True}, None),
+ ("FALLOFF_GEODESICS", {"type": 'ONE', "value": 'PRESS', "any": True}, None),
+ ("FALLOFF_TOPOLOGY", {"type": 'TWO', "value": 'PRESS', "any": True}, None),
+ ("FALLOFF_TOPOLOGY_DIAGONALS", {"type": 'THREE', "value": 'PRESS', "any": True}, None),
+ ("FALLOFF_SPHERICAL", {"type": 'FOUR', "value": 'PRESS', "any": True}, None),
+ ("SNAP_TOGGLE", {"type": 'LEFT_CTRL', "value": 'ANY'}, None),
+ ("LOOP_COUNT_INCREASE", {"type": 'W', "value": 'PRESS', "any": True, "repeat": True}, None),
+ ("LOOP_COUNT_DECREASE", {"type": 'Q', "value": 'PRESS', "any": True, "repeat": True}, None),
+ ("BRUSH_GRADIENT_TOGGLE", {"type": 'B', "value": 'PRESS', "any": True}, None),
+ ("TEXTURE_DISTORTION_INCREASE", {"type": 'Y', "value": 'PRESS'}, None),
+ ("TEXTURE_DISTORTION_DECREASE", {"type": 'T', "value": 'PRESS'}, None),
])
return keymap
-
-
# Fallback for gizmos that don't have custom a custom key-map.
def km_generic_gizmo(_params):
keymap = (
@@ -5712,7 +5718,7 @@ def km_popup_toolbar(_params):
def km_generic_tool_annotate(params):
return (
"Generic Tool: Annotate",
- {"region_type": 'WINDOW'},
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": [
("gpencil.annotate", {"type": params.tool_mouse, "value": 'PRESS'},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
@@ -5725,7 +5731,7 @@ def km_generic_tool_annotate(params):
def km_generic_tool_annotate_line(params):
return (
"Generic Tool: Annotate Line",
- {"region_type": 'WINDOW'},
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": [
("gpencil.annotate", {"type": params.tool_tweak, "value": 'ANY'},
{"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
@@ -5738,7 +5744,7 @@ def km_generic_tool_annotate_line(params):
def km_generic_tool_annotate_polygon(params):
return (
"Generic Tool: Annotate Polygon",
- {"region_type": 'WINDOW'},
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": [
("gpencil.annotate", {"type": params.tool_mouse, "value": 'PRESS'},
{"properties": [("mode", 'DRAW_POLY'), ("wait_for_input", False)]}),
@@ -5751,7 +5757,7 @@ def km_generic_tool_annotate_polygon(params):
def km_generic_tool_annotate_eraser(params):
return (
"Generic Tool: Annotate Eraser",
- {"region_type": 'WINDOW'},
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": [
("gpencil.annotate", {"type": params.tool_mouse, "value": 'PRESS'},
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 234781b7bc8..91f153a0f42 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -161,12 +161,12 @@ def _template_items_tool_select_actions(operator, *, type, value):
# This could have a more generic name, for now use for circle select.
-def _template_items_tool_select_actions_simple(operator, *, type, value, properties=[]):
+def _template_items_tool_select_actions_simple(operator, *, type, value, properties=()):
kmi_args = {"type": type, "value": value}
return [
# Don't define 'SET' here, take from the tool options.
(operator, kmi_args,
- {"properties": properties}),
+ {"properties": [*properties]}),
(operator, {**kmi_args, "shift": True},
{"properties": [*properties, ("mode", 'ADD')]}),
(operator, {**kmi_args, "ctrl": True},
@@ -1113,6 +1113,7 @@ def km_node_editor(params):
("node.resize", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("node.add_reroute", {"type": params.action_tweak, "value": 'ANY', "shift": True}, None),
("node.links_cut", {"type": params.action_tweak, "value": 'ANY', "ctrl": True}, None),
+ ("node.links_mute", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("node.backimage_fit", {"type": 'A', "value": 'PRESS', "alt": True}, None),
("node.backimage_sample", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
@@ -1309,6 +1310,7 @@ def km_file_browser_main(params):
{"properties": [("mode", 'ADD')]}),
("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
+ ("file.view_selected", {"type": 'F', "value": 'PRESS'}, None),
])
return keymap
@@ -1911,7 +1913,7 @@ def km_console(params):
("console.delete", {"type": 'BACK_SPACE', "value": 'PRESS', "repeat": True},
{"properties": [("type", 'PREVIOUS_CHARACTER')]}),
("console.delete", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True, "repeat": True},
- {"properties": [("type", 'PREVIOUS_CHARACTER')], "repeat": True}),
+ {"properties": [("type", 'PREVIOUS_CHARACTER')]}),
("console.delete", {"type": 'DEL', "value": 'PRESS', "ctrl": True, "repeat": True},
{"properties": [("type", 'NEXT_WORD')]}),
("console.delete", {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True, "repeat": True},
@@ -3394,7 +3396,8 @@ def km_sculpt(params):
{"properties": [("data_path", 'scene.tool_settings.sculpt.show_mask')]}),
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
- ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("sculpt.dyntopo_detail_size_edit", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True, "alt": True}, None),
# Remesh
("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
@@ -3847,10 +3850,10 @@ def km_knife_tool_modal_map(_params):
("ADD_CUT_CLOSED", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "any": True}, None),
("ADD_CUT", {"type": 'LEFTMOUSE', "value": 'ANY', "any": True}, None),
("NEW_CUT", {"type": 'E', "value": 'PRESS'}, None),
- ("SNAP_MIDPOINTS_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": False}, None),
- ("SNAP_MIDPOINTS_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": False}, None),
- ("SNAP_MIDPOINTS_ON", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": False}, None),
- ("SNAP_MIDPOINTS_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": False}, None),
+ ("SNAP_MIDPOINTS_ON", {"type": 'LEFT_CTRL', "value": 'PRESS'}, None),
+ ("SNAP_MIDPOINTS_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE'}, None),
+ ("SNAP_MIDPOINTS_ON", {"type": 'RIGHT_CTRL', "value": 'PRESS'}, None),
+ ("SNAP_MIDPOINTS_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE'}, None),
("IGNORE_SNAP_ON", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
("IGNORE_SNAP_OFF", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
("IGNORE_SNAP_ON", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
diff --git a/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py b/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py
index 9b0a260dc95..192ba2cf5b5 100644
--- a/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py
+++ b/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py
@@ -58,6 +58,7 @@ def load_handler(dummy):
# Grease pencil object
scene = bpy.data.scenes[0]
if scene:
+ scene.tool_settings.use_keyframe_insert_auto = True
for ob in scene.objects:
if ob.type == 'GPENCIL':
gpd = ob.data
diff --git a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py
index bfad66ec6cd..c97c3466085 100644
--- a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py
+++ b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py
@@ -22,7 +22,6 @@ from bpy.app.handlers import persistent
@persistent
def load_handler(dummy):
- import os
from bpy import context
screen = context.screen
for area in screen.areas:
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 7e6f14a0a51..078b32f5e2a 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -45,6 +45,7 @@ _modules = [
"rigidbody",
"screen_play_rendered_anim",
"sequencer",
+ "spreadsheet",
"userpref",
"uvcalc_follow_active",
"uvcalc_lightmap",
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index 85290bfe3f0..0b6b92cfd7e 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -438,7 +438,7 @@ class ANIM_OT_show_group_colors_deprecated(Operator):
bl_options = {'REGISTER'}
@classmethod
- def poll(cls, context) -> bool:
+ def poll(cls, context):
return False
diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py
index 231dade820d..cd6728d56b2 100644
--- a/release/scripts/startup/bl_operators/console.py
+++ b/release/scripts/startup/bl_operators/console.py
@@ -37,6 +37,7 @@ class ConsoleExec(Operator):
"""Execute the current console line as a python expression"""
bl_idname = "console.execute"
bl_label = "Console Execute"
+ bl_options = {'UNDO_GROUPED'}
interactive: BoolProperty(
options={'SKIP_SAVE'},
diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py
index 9652f23aadb..4ced3cb5957 100644
--- a/release/scripts/startup/bl_operators/geometry_nodes.py
+++ b/release/scripts/startup/bl_operators/geometry_nodes.py
@@ -19,7 +19,7 @@
import bpy
-def geometry_node_group_empty_new(context):
+def geometry_node_group_empty_new():
group = bpy.data.node_groups.new("Geometry Nodes", 'GeometryNodeTree')
group.inputs.new('NodeSocketGeometry', "Geometry")
group.outputs.new('NodeSocketGeometry', "Geometry")
@@ -38,7 +38,7 @@ def geometry_node_group_empty_new(context):
return group
-def geometry_modifier_poll(context) -> bool:
+def geometry_modifier_poll(context):
ob = context.object
# Test object support for geometry node modifier (No volume, curve, or hair object support yet)
@@ -85,7 +85,7 @@ class NewGeometryNodeTreeAssign(bpy.types.Operator):
if not modifier:
return {'CANCELLED'}
- group = geometry_node_group_empty_new(context)
+ group = geometry_node_group_empty_new()
modifier.node_group = group
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index 70b80f7198f..4a7700b03bb 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -19,7 +19,6 @@
# <pep8-80 compliant>
-import bpy
from bpy.types import Operator
from mathutils import Vector
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 48312f958ef..a34ed019148 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -25,7 +25,6 @@ from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
- FloatVectorProperty,
IntProperty,
)
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 5132b358f5e..cedbe542287 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -384,7 +384,7 @@ class AddPresetFluid(AddPresetBase, Operator):
"""Add or remove a Fluid Preset"""
bl_idname = "fluid.preset_add"
bl_label = "Add Fluid Preset"
- preset_menu = "FLUID_MT_presets"
+ preset_menu = "FLUID_PT_presets"
preset_defines = [
"fluid = bpy.context.fluid"
diff --git a/release/scripts/startup/bl_operators/spreadsheet.py b/release/scripts/startup/bl_operators/spreadsheet.py
new file mode 100644
index 00000000000..fa6568f6f11
--- /dev/null
+++ b/release/scripts/startup/bl_operators/spreadsheet.py
@@ -0,0 +1,52 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+from __future__ import annotations
+
+import bpy
+
+class SPREADSHEET_OT_toggle_pin(bpy.types.Operator):
+ '''Turn on or off pinning'''
+ bl_idname = "spreadsheet.toggle_pin"
+ bl_label = "Toggle Pin"
+ bl_options = {'REGISTER'}
+
+ @classmethod
+ def poll(cls, context):
+ space = context.space_data
+ return space and space.type == 'SPREADSHEET'
+
+ def execute(self, context):
+ space = context.space_data
+
+ if space.pinned_id:
+ space.pinned_id = None
+ else:
+ space.pinned_id = context.active_object
+
+ return {'FINISHED'}
+
+
+classes = (
+ SPREADSHEET_OT_toggle_pin,
+)
+
+if __name__ == "__main__": # Only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index 4343717f264..1b801f77e07 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -18,7 +18,6 @@
# <pep8 compliant>
-import bpy
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index 3442e189d14..ff5bcdb034f 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -169,7 +169,7 @@ class VIEW3D_OT_edit_mesh_extrude_manifold_normal(Operator):
obj = context.active_object
return (obj is not None and obj.mode == 'EDIT')
- def execute(self, context):
+ def execute(self, _context):
bpy.ops.mesh.extrude_manifold(
'INVOKE_REGION_WIN',
MESH_OT_extrude_region={
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 06b3b4defcc..2f97942faa4 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -860,7 +860,9 @@ class WM_OT_url_open_preset(Operator):
type: EnumProperty(
name="Site",
- items=WM_OT_url_open_preset._preset_items,
+ items=lambda self, _context: (
+ item for (item, _) in WM_OT_url_open_preset.preset_items
+ ),
)
id: StringProperty(
@@ -915,10 +917,6 @@ class WM_OT_url_open_preset(Operator):
"https://www.blender.org/about/credits/"),
]
- @staticmethod
- def _preset_items(_self, _context):
- return (item for (item, _) in WM_OT_url_open_preset.preset_items)
-
def execute(self, context):
url = None
type = self.type
@@ -1220,14 +1218,11 @@ class WM_OT_properties_edit(Operator):
)
subtype: EnumProperty(
name="Subtype",
- items=WM_OT_properties_edit._subtype_items_fn,
+ items=lambda self, _context: WM_OT_properties_edit.subtype_items,
)
subtype_items = rna_vector_subtype_items
- def _subtype_items_fn(_self, _context):
- return WM_OT_properties_edit.subtype_items
-
def _init_subtype(self, prop_type, is_array, subtype):
subtype = subtype or 'NONE'
subtype_items = rna_vector_subtype_items
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 7d3ecceca41..86c376bcb21 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -67,6 +67,7 @@ _modules = [
"properties_scene",
"properties_texture",
"properties_world",
+ "properties_collection",
# Generic Space Modules
#
@@ -86,6 +87,7 @@ _modules = [
"space_outliner",
"space_properties",
"space_sequencer",
+ "space_spreadsheet",
"space_statusbar",
"space_text",
"space_time",
@@ -103,6 +105,8 @@ import bpy
if bpy.app.build_options.freestyle:
_modules.append("properties_freestyle")
+_modules.append("properties_lineart")
+
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
_modules_loaded = [_namespace[name] for name in _modules]
diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py
new file mode 100644
index 00000000000..186314f9591
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_collection.py
@@ -0,0 +1,100 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+from bpy.types import Panel
+
+
+class CollectionButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "collection"
+
+
+def lineart_make_line_type_entry(col, line_type, text_disp, expand, search_from):
+ col.prop(line_type, "use", text=text_disp)
+ if line_type.use and expand:
+ col.prop_search(line_type, "layer", search_from,
+ "layers", icon='GREASEPENCIL')
+ col.prop_search(line_type, "material", search_from,
+ "materials", icon='SHADING_TEXTURE')
+
+
+class COLLECTION_PT_collection_flags(CollectionButtonsPanel, Panel):
+ bl_label = "Restrictions"
+
+ @classmethod
+ def poll(cls, context):
+ vl = context.view_layer
+ vlc = vl.active_layer_collection
+ return (vlc.name != 'Master Collection')
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ collection = context.collection
+ vl = context.view_layer
+ vlc = vl.active_layer_collection
+
+ col = layout.column(align=True)
+ col.prop(collection, "hide_select", text="Selectable", toggle=False, invert_checkbox=True)
+ col.prop(collection, "hide_render", toggle=False)
+
+ col = layout.column(align=True)
+ col.prop(vlc, "holdout", toggle=False)
+ col.prop(vlc, "indirect_only", toggle=False)
+
+
+class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
+ bl_label = "Instancing"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+ collection = context.collection
+
+ row = layout.row()
+ row.prop(collection, "instance_offset")
+
+
+class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
+ bl_label = "Line Art"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+ collection = context.collection
+
+ row = layout.row()
+ row.prop(collection, "lineart_usage")
+
+
+classes = (
+ COLLECTION_PT_collection_flags,
+ COLLECTION_PT_instancing,
+ COLLECTION_PT_lineart_collection,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index e8c62368239..e835e577953 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -42,7 +42,7 @@ class OBJECT_PT_constraints(ObjectConstraintPanel, Panel):
bl_label = "Object Constraints"
bl_options = {'HIDE_HEADER'}
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
@@ -56,7 +56,7 @@ class BONE_PT_constraints(BoneConstraintPanel, Panel):
bl_label = "Bone Constraints"
bl_options = {'HIDE_HEADER'}
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
@@ -122,7 +122,7 @@ class ConstraintButtonsPanel:
elif con.target.type in {'MESH', 'LATTICE'}:
col.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
- def get_constraint(self, context):
+ def get_constraint(self, _context):
con = self.custom_data
self.layout.context_pointer_set("constraint", con)
return con
@@ -844,7 +844,7 @@ class ConstraintButtonsPanel:
self.draw_influence(layout, con)
- def draw_python_constraint(self, context):
+ def draw_python_constraint(self, _context):
layout = self.layout
layout.label(text="Blender 2.6 doesn't support python constraints yet")
@@ -976,7 +976,7 @@ class ConstraintButtonsSubPanel:
bl_label = ""
bl_options = {'DRAW_BOX'}
- def get_constraint(self, context):
+ def get_constraint(self, _context):
con = self.custom_data
self.layout.context_pointer_set("constraint", con)
return con
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 170d7910339..f3e116ca321 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -255,17 +255,11 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
- ob = context.object
bone = context.bone
- pchan = None
-
- if ob and bone:
- pchan = ob.pose.bones[bone.name]
- elif bone is None:
+ if bone is None:
bone = context.edit_bone
if bone:
-
col = layout.column()
col.prop(bone, "hide", text="Hide", toggle=False)
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index 9db6eedb04c..69720a6c54b 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -392,7 +392,6 @@ class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
layout.use_property_decorate = False
gpd = context.gpencil
- gpl = gpd.layers.active
layout.prop(gpd, "edit_line_color", text="Edit Line Color")
diff --git a/release/scripts/startup/bl_ui/properties_data_hair.py b/release/scripts/startup/bl_ui/properties_data_hair.py
index 4964316ad0f..7f95fad9a9e 100644
--- a/release/scripts/startup/bl_ui/properties_data_hair.py
+++ b/release/scripts/startup/bl_ui/properties_data_hair.py
@@ -81,7 +81,7 @@ class HAIR_MT_add_attribute(Menu):
class HAIR_UL_attributes(UIList):
- def draw_item(self, context, layout, data, attribute, icon, active_data, active_propname, index):
+ def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
domain = attribute.bl_rna.properties['domain'].enum_items[attribute.domain]
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index d464a3ffc6b..39250559741 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -17,9 +17,7 @@
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
-import bpy
from bpy.types import Panel
-from bpy.app.translations import pgettext_iface as iface_
class ModifierButtonsPanel:
@@ -37,7 +35,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
ob = context.object
return ob and ob.type != 'GPENCIL'
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("object.modifier_add", "type")
layout.template_modifiers()
@@ -51,7 +49,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
ob = context.object
return ob and ob.type == 'GPENCIL'
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("object.gpencil_modifier_add", "type")
layout.template_grease_pencil_modifiers()
diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
index eca59ea4aaf..f0584c81c0c 100644
--- a/release/scripts/startup/bl_ui/properties_data_pointcloud.py
+++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
@@ -83,7 +83,7 @@ class POINTCLOUD_MT_add_attribute(Menu):
class POINTCLOUD_UL_attributes(UIList):
- def draw_item(self, context, layout, data, attribute, icon, active_data, active_propname, index):
+ def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
split = layout.split(factor=0.75)
diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
index a96fef018c7..576910697ad 100644
--- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py
+++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
@@ -37,7 +37,7 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
# ob = context.object
# return ob and ob.type == 'GPENCIL'
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("object.shaderfx_add", "type")
layout.template_shaderfx()
diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py
index e7bf9adb876..70056b1d27c 100644
--- a/release/scripts/startup/bl_ui/properties_data_volume.py
+++ b/release/scripts/startup/bl_ui/properties_data_volume.py
@@ -84,7 +84,7 @@ class DATA_PT_volume_file(DataButtonsPanel, Panel):
class VOLUME_UL_grids(UIList):
- def draw_item(self, context, layout, data, grid, icon, active_data, active_propname, index):
+ def draw_item(self, _context, layout, _data, grid, _icon, _active_data, _active_propname, _index):
name = grid.name
data_type = grid.bl_rna.properties['data_type'].enum_items[grid.data_type]
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 0eb5d60457c..c23cc838e51 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -37,8 +37,6 @@ class AnnotationDrawingToolsPanel:
tool_settings = context.tool_settings
- is_clip_editor = context.space_data.type == 'CLIP_EDITOR'
-
col = layout.column(align=True)
col.label(text="Draw:")
@@ -337,7 +335,6 @@ class GPENCIL_MT_material_active(Menu):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
ob = context.active_object
- mat_active = ob.active_material
for slot in ob.material_slots:
mat = slot.material
diff --git a/release/scripts/startup/bl_ui/properties_lineart.py b/release/scripts/startup/bl_ui/properties_lineart.py
new file mode 100644
index 00000000000..7c4d6c7be0b
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_lineart.py
@@ -0,0 +1,59 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+from bpy.types import Panel
+
+
+class LineartButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "object"
+
+
+class OBJECT_PT_lineart(LineartButtonsPanel, Panel):
+ bl_label = "Line Art"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob.type in {'MESH', 'FONT', 'CURVE', 'SURFACE'})
+
+ def draw(self, context):
+ layout = self.layout
+ lineart = context.object.lineart
+
+ layout.use_property_split = True
+
+ layout.prop(lineart, 'usage')
+ layout.use_property_split = True
+
+ row = layout.row(heading="Override Crease")
+ row.prop(lineart, "use_crease_override", text="")
+ row.prop(lineart, "crease_threshold", slider=True, text="")
+
+
+classes = (
+ OBJECT_PT_lineart,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index 4d25b8ca309..09a1f40d3a9 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -26,7 +26,7 @@ from bpy.app.translations import contexts as i18n_contexts
# Use by both image & clip context menus.
-def draw_mask_context_menu(layout, context):
+def draw_mask_context_menu(layout, _context):
layout.operator_menu_enum("mask.handle_type_set", "type")
layout.operator("mask.switch_direction")
layout.operator("mask.cyclic_toggle")
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 47ab98386f4..ebd91143239 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -274,6 +274,38 @@ class MATERIAL_PT_viewport(MaterialButtonsPanel, Panel):
col.prop(mat, "roughness")
+class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel):
+ bl_label = "Line Art"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ return mat and not mat.grease_pencil
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material
+ lineart = mat.lineart
+
+ layout.prop(lineart, "use_transparency")
+
+ if lineart.use_transparency:
+
+ layout.label(text="Transparency Masks:")
+
+ row = layout.row(align=True)
+ row.prop(lineart, "transparency_mask_0", text="0", toggle=True)
+ row.prop(lineart, "transparency_mask_1", text="1", toggle=True)
+ row.prop(lineart, "transparency_mask_2", text="2", toggle=True)
+ row.prop(lineart, "transparency_mask_3", text="3", toggle=True)
+ row.prop(lineart, "transparency_mask_4", text="4", toggle=True)
+ row.prop(lineart, "transparency_mask_5", text="5", toggle=True)
+ row.prop(lineart, "transparency_mask_6", text="6", toggle=True)
+ row.prop(lineart, "transparency_mask_7", text="7", toggle=True)
+
+
classes = (
MATERIAL_MT_context_menu,
MATERIAL_UL_matslots,
@@ -282,6 +314,7 @@ classes = (
EEVEE_MATERIAL_PT_surface,
EEVEE_MATERIAL_PT_volume,
EEVEE_MATERIAL_PT_settings,
+ MATERIAL_PT_lineart,
MATERIAL_PT_viewport,
EEVEE_MATERIAL_PT_viewport_settings,
MATERIAL_PT_custom_props,
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index 69c557d336f..75c1f69f84f 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -80,7 +80,7 @@ class RENDER_PT_dimensions(RenderOutputButtonsPanel, Panel):
fps_rate = round(fps / fps_base, 2)
# TODO: Change the following to iterate over existing presets
- custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60})
+ custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60, 120, 240})
if custom_framerate is True:
fps_label_text = tip_("Custom (%.4g fps)") % fps_rate
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index dfdc6ab79f4..6989139d447 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -277,11 +277,10 @@ class TextureMaskPanel(BrushPanel):
layout.use_property_decorate = False
brush = context.tool_settings.image_paint.brush
+ mask_tex_slot = brush.mask_texture_slot
col = layout.column()
- col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
-
- mask_tex_slot = brush.mask_texture_slot
+ col.template_ID_preview(mask_tex_slot, "texture", new="texture.new", rows=3, cols=8)
# map_mode
layout.row().prop(mask_tex_slot, "mask_map_mode", text="Mask Mapping")
@@ -614,7 +613,6 @@ def brush_settings(layout, context, brush, popover=False):
# use_persistent, set_persistent_base
if capabilities.has_persistence:
- ob = context.sculpt_object
layout.separator()
layout.prop(brush, "use_persistent")
layout.operator("sculpt.set_persistent_base")
@@ -1283,7 +1281,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True)
-def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False):
+def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False):
gp_settings = brush.gpencil_settings
tool = brush.gpencil_sculpt_tool
@@ -1318,7 +1316,6 @@ def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False
def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=False):
- gp_settings = brush.gpencil_settings
layout.prop(brush, "size", slider=True)
row = layout.row(align=True)
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 60caa39b723..a9f040db9b5 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -1263,6 +1263,8 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
if (
part.type == 'EMITTER' or
+ part.type in {'FLIP', 'SPRAY', 'BUBBLE', 'FOAM', 'TRACER',
+ 'SPRAYFOAM', 'SPRAYBUBBLE', 'FOAMBUBBLE', 'SPRAYFOAMBUBBLE'} or
(part.render_type in {'OBJECT', 'COLLECTION'} and part.type == 'HAIR')
):
if part.render_type != 'NONE':
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index 5d3417fad0f..d168d9ab6dd 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Panel
from bl_ui.utils import PresetPanel
from .properties_physics_common import (
effector_weights_ui,
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
index 8c39684583f..ad7d6008238 100644
--- a/release/scripts/startup/bl_ui/properties_view_layer.py
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -21,7 +21,7 @@ from bpy.types import Panel, UIList
class VIEWLAYER_UL_aov(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname):
row = layout.row()
split = row.split(factor=0.65)
icon = 'NONE' if item.is_valid else 'ERROR'
@@ -77,8 +77,6 @@ class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- scene = context.scene
- rd = scene.render
view_layer = context.view_layer
col = layout.column()
@@ -101,8 +99,6 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
view_layer = context.view_layer
view_layer_eevee = view_layer.eevee
- scene = context.scene
- scene_eevee = scene.eevee
col = layout.column(heading="Diffuse", align=True)
col.prop(view_layer, "use_pass_diffuse_direct", text="Light")
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 39d232b2871..f7ba9ebcb43 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -598,6 +598,7 @@ class DOPESHEET_MT_context_menu(Menu):
def draw(self, _context):
layout = self.layout
+ st = _context.space_data
layout.operator_context = 'INVOKE_DEFAULT'
@@ -608,17 +609,27 @@ class DOPESHEET_MT_context_menu(Menu):
layout.separator()
layout.operator_menu_enum("action.keyframe_type", "type", text="Keyframe Type")
- layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
- layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
- layout.operator_menu_enum("action.easing_type", "type", text="Easing Mode")
+
+ if st.mode != 'GPENCIL':
+ layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("action.easing_type", "type", text="Easing Mode")
layout.separator()
layout.operator("action.keyframe_insert").type = 'SEL'
layout.operator("action.duplicate_move")
+
+ if st.mode == 'GPENCIL':
+ layout.separator()
+
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("action.delete")
+ if st.mode == 'GPENCIL':
+ layout.operator("gpencil.interpolate_reverse")
+ layout.operator("gpencil.frame_clean_duplicate", text="Delete Duplicate Frames")
+
layout.separator()
layout.operator_menu_enum("action.mirror", "type", text="Mirror")
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index ef4f47c9399..b236b2ee7cf 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -494,6 +494,7 @@ class FILEBROWSER_MT_view(Menu):
layout.prop(st, "show_region_toolbar", text="Source List")
layout.prop(st, "show_region_ui", text="File Path")
+ layout.operator("file.view_selected")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 6ece6a4c841..31e81d1454e 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -135,6 +135,8 @@ class GRAPH_MT_view(Menu):
layout.separator()
+ layout.prop(st, "show_extrapolation")
+
layout.prop(st, "show_handles")
layout.prop(st, "use_only_selected_curves_handles")
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 73cc674858c..e7589709130 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -375,7 +375,7 @@ class IMAGE_MT_uvs_split(Menu):
class IMAGE_MT_uvs_unwrap(Menu):
bl_label = "Unwrap"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("uv.unwrap")
@@ -1189,9 +1189,10 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
tool_settings = context.tool_settings.image_paint
brush = tool_settings.brush
+ tex_slot = brush.texture_slot
col = layout.column()
- col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
+ col.template_ID_preview(tex_slot, "texture", new="texture.new", rows=3, cols=8)
brush_texture_settings(col, brush, 0)
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index a9934850acd..7f66cdd3d74 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -331,6 +331,7 @@ class NODE_MT_node(Menu):
layout.operator("node.link_make", text="Make and Replace Links").replace = True
layout.operator("node.links_cut")
layout.operator("node.links_detach")
+ layout.operator("node.links_mute")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 43a5e17e50e..5c5a78f3942 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -19,10 +19,6 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
-from bpy.app.translations import (
- contexts as i18n_contexts,
- pgettext_iface as iface_,
-)
class OUTLINER_HT_header(Header):
@@ -257,7 +253,7 @@ class OUTLINER_MT_collection_new(Menu):
bl_label = "Collection"
@staticmethod
- def draw_without_context_menu(context, layout):
+ def draw_without_context_menu(_context, layout):
layout.operator("outliner.collection_new", text="New Collection").nested = True
layout.operator("outliner.id_paste", text="Paste Data-Blocks", icon='PASTEDOWN')
@@ -278,7 +274,6 @@ class OUTLINER_MT_object(Menu):
layout = self.layout
space = context.space_data
- obj = context.active_object
layout.operator("outliner.id_copy", text="Copy", icon='COPYDOWN')
layout.operator("outliner.id_paste", text="Paste", icon='PASTEDOWN')
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index e10f3383bc8..a4c2ed68a91 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -113,6 +113,10 @@ class SEQUENCER_HT_tool_header(Header):
# TODO: options popover.
def draw_tool_settings(self, context):
+ pass
+
+ # Currently unused.
+ '''
layout = self.layout
# Active Tool
@@ -120,6 +124,7 @@ class SEQUENCER_HT_tool_header(Header):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
tool_mode = context.mode if tool is None else tool.mode
+ '''
class SEQUENCER_HT_header(Header):
@@ -129,8 +134,6 @@ class SEQUENCER_HT_header(Header):
layout = self.layout
st = context.space_data
- scene = context.scene
- sequencer_tool_settings = context.tool_settings.sequencer_tool_settings
show_region_tool_header = st.show_region_tool_header
@@ -336,8 +339,6 @@ class SEQUENCER_MT_view(Menu):
st = context.space_data
is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}
- scene = context.scene
- ed = scene.sequence_editor
if st.view_type == 'PREVIEW':
# Specifying the REGION_PREVIEW context is needed in preview-only
@@ -1904,7 +1905,6 @@ class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel):
if strip.proxy:
proxy = strip.proxy
- flow = layout.column_flow()
if ed.proxy_storage == 'PER_STRIP':
col = layout.column(heading="Custom Proxy")
col.prop(proxy, "use_proxy_custom_directory", text="Directory")
@@ -2000,6 +2000,17 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
ed = context.scene.sequence_editor
col = layout.column()
+ col.prop(st, "proxy_render_size")
+
+ col = layout.column()
+ prop = col.prop(st, "use_proxies")
+ if st.proxy_render_size in ('NONE', 'SCENE'):
+ col.enabled = False
+
+ col = layout.column()
+ if ed:
+ col.prop(ed, "use_prefetch")
+
col.prop(st, "display_channel", text="Channel")
if st.display_mode == 'IMAGE':
@@ -2008,11 +2019,6 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
elif st.display_mode == 'WAVEFORM':
col.prop(st, "show_separate_color")
- col.prop(st, "proxy_render_size")
-
- if ed:
- col.prop(ed, "use_prefetch")
-
class SEQUENCER_PT_frame_overlay(SequencerButtonsPanel_Output, Panel):
bl_label = "Frame Overlay"
diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py
new file mode 100644
index 00000000000..a12fe68c9a5
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_spreadsheet.py
@@ -0,0 +1,57 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+
+class SPREADSHEET_HT_header(bpy.types.Header):
+ bl_space_type = 'SPREADSHEET'
+
+ def draw(self, context):
+ layout = self.layout
+ space = context.space_data
+
+ layout.template_header()
+
+ pinned_id = space.pinned_id
+ used_id = pinned_id if pinned_id else context.active_object
+
+ layout.prop(space, "object_eval_state", text="")
+ if space.object_eval_state != "ORIGINAL":
+ layout.prop(space, "geometry_component_type", text="")
+ layout.prop(space, "attribute_domain", text="")
+
+ if used_id:
+ layout.label(text=used_id.name, icon="OBJECT_DATA")
+
+ layout.operator("spreadsheet.toggle_pin", text="", icon='PINNED' if pinned_id else 'UNPINNED', emboss=False)
+
+ layout.separator_spacer()
+
+ if isinstance(used_id, bpy.types.Object) and used_id.mode == 'EDIT':
+ layout.prop(space, "show_only_selected", text="Selected Only")
+
+
+classes = (
+ SPREADSHEET_HT_header,
+)
+
+if __name__ == "__main__": # Only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 8e99c3af4c3..1e52142c85c 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1096,7 +1096,7 @@ class _defs_edit_curve:
@ToolDef.from_fn
def draw():
- def draw_settings(context, layout, tool, *, extra=False):
+ def draw_settings(context, layout, _tool, *, extra=False):
# Tool settings initialize operator options.
tool_settings = context.tool_settings
cps = tool_settings.curve_paint_settings
@@ -1589,7 +1589,7 @@ class _defs_weight_paint:
@ToolDef.from_fn
def sample_weight():
- def draw_settings(context, layout, tool):
+ def draw_settings(context, layout, _tool):
if context.tool_settings.unified_paint_settings.use_unified_weight:
weight = context.tool_settings.unified_paint_settings.weight
elif context.tool_settings.weight_paint.brush:
@@ -1869,7 +1869,7 @@ class _defs_image_uv_sculpt:
class _defs_gpencil_paint:
@staticmethod
- def gpencil_primitive_toolbar(context, layout, tool, props):
+ def gpencil_primitive_toolbar(context, layout, _tool, props):
paint = context.tool_settings.gpencil_paint
brush = paint.brush
@@ -1907,7 +1907,7 @@ class _defs_gpencil_paint:
@ToolDef.from_fn
def cutter():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("gpencil.stroke_cutter")
row = layout.row()
row.use_property_split = False
@@ -2020,7 +2020,7 @@ class _defs_gpencil_paint:
@ToolDef.from_fn
def eyedropper():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("ui.eyedropper_gpencil_color")
row = layout.row()
row.use_property_split = False
@@ -2037,7 +2037,7 @@ class _defs_gpencil_paint:
@ToolDef.from_fn
def interpolate():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("gpencil.interpolate")
layout.prop(props, "layers")
layout.prop(props, "flip")
@@ -2201,7 +2201,7 @@ class _defs_gpencil_edit:
@ToolDef.from_fn
def transform_fill():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("gpencil.transform_fill")
row = layout.row()
row.use_property_split = False
@@ -2219,7 +2219,7 @@ class _defs_gpencil_edit:
@ToolDef.from_fn
def interpolate():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("gpencil.interpolate")
layout.prop(props, "layers")
layout.prop(props, "interpolate_selected_only")
@@ -2411,8 +2411,6 @@ class _defs_sequencer_generic:
@ToolDef.from_fn
def sample():
- def draw_settings(_context, layout, tool):
- props = tool.operator_properties("sequencer.sample")
return dict(
idname="builtin.sample",
label="Sample",
@@ -2421,7 +2419,6 @@ class _defs_sequencer_generic:
),
icon="ops.paint.weight_sample", # XXX, needs own icon.
keymap="Sequencer Tool: Sample",
- draw_settings=draw_settings,
)
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 45460a1a5de..7219922c379 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -244,7 +244,7 @@ class TOPBAR_MT_app(Menu):
class TOPBAR_MT_file_cleanup(Menu):
bl_label = "Clean Up"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.separator()
@@ -475,7 +475,7 @@ class TOPBAR_MT_file_export(Menu):
bl_label = "Export"
bl_owner_use_filter = False
- def draw(self, context):
+ def draw(self, _context):
if bpy.app.build_options.collada:
self.layout.operator("wm.collada_export",
text="Collada (Default) (.dae)")
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 94a1e2bec4d..96695ff1be5 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -96,7 +96,7 @@ class USERPREF_MT_editor_menus(Menu):
class USERPREF_MT_view(Menu):
bl_label = "View"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.menu("INFO_MT_area")
@@ -241,7 +241,7 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel)
bl_translation_context = i18n_contexts.id_windowmanager
@classmethod
- def poll(cls, context):
+ def poll(cls, _context):
return bpy.app.build_options.international
def draw_centered(self, context, layout):
@@ -581,7 +581,7 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Cycles Render Devices"
@classmethod
- def poll(cls, context):
+ def poll(cls, _context):
# No GPU rendering on macOS currently.
import sys
return bpy.app.build_options.cycles and sys.platform != "darwin"
@@ -642,7 +642,7 @@ class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel):
def draw_centered(self, context, layout):
prefs = context.preferences
system = prefs.system
- edit = prefs.edit
+ # edit = prefs.edit
layout.prop(system, "memory_cache_limit")
@@ -655,6 +655,10 @@ class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel):
col.prop(system, "sequencer_disk_cache_size_limit", text="Cache Limit")
col.prop(system, "sequencer_disk_cache_compression", text="Compression")
+ layout.separator()
+
+ layout.prop(system, "sequencer_proxy_setup")
+
# -----------------------------------------------------------------------------
# Viewport Panels
@@ -2185,7 +2189,7 @@ class ExperimentalPanel:
url_prefix = "https://developer.blender.org/"
@classmethod
- def poll(cls, context):
+ def poll(cls, _context):
return bpy.app.version_cycle == 'alpha'
def _draw_items(self, context, items):
@@ -2260,7 +2264,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
bl_label = "Debugging"
@classmethod
- def poll(cls, context):
+ def poll(cls, _context):
# Unlike the other experimental panels, the debugging one is always visible
# even in beta or release.
return True
@@ -2269,6 +2273,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
self._draw_items(
context, (
({"property": "use_undo_legacy"}, "T60695"),
+ ({"property": "override_auto_resync"}, "T83811"),
({"property": "use_cycles_debug"}, None),
),
)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 41a1831f46a..fb0374695ed 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1068,7 +1068,7 @@ class VIEW3D_MT_snap(Menu):
class VIEW3D_MT_uv_map(Menu):
bl_label = "UV Mapping"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("uv.unwrap")
@@ -1822,7 +1822,7 @@ class VIEW3D_MT_select_edit_armature(Menu):
class VIEW3D_MT_paint_gpencil(Menu):
bl_label = "Paint"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors")
@@ -2238,7 +2238,7 @@ class VIEW3D_MT_object(Menu):
bl_context = "objectmode"
bl_label = "Object"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.menu("VIEW3D_MT_transform_object")
@@ -2717,7 +2717,7 @@ class VIEW3D_MT_object_constraints(Menu):
class VIEW3D_MT_object_quick_effects(Menu):
bl_label = "Quick Effects"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("object.quick_fur")
@@ -3121,6 +3121,11 @@ class VIEW3D_MT_mask(Menu):
props = layout.operator("sculpt.dirty_mask", text='Dirty Mask')
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_random_mask", text="Random Mask")
+
+
class VIEW3D_MT_face_sets(Menu):
bl_label = "Face Sets"
@@ -3139,7 +3144,7 @@ class VIEW3D_MT_face_sets(Menu):
layout.separator()
- layout.menu("VIEW3D_MT_face_sets_init", text="Init Face Sets")
+ layout.menu("VIEW3D_MT_face_sets_init", text="Initialize Face Sets")
layout.separator()
@@ -3197,6 +3202,9 @@ class VIEW3D_MT_face_sets_init(Menu):
op = layout.operator("sculpt.face_sets_init", text='By Loose Parts')
op.mode = 'LOOSE_PARTS'
+ op = layout.operator("sculpt.face_sets_init", text='By Face Set Boundaries')
+ op.mode = 'FACE_SET_BOUNDARIES'
+
op = layout.operator("sculpt.face_sets_init", text='By Materials')
op.mode = 'MATERIALS'
@@ -3219,6 +3227,21 @@ class VIEW3D_MT_face_sets_init(Menu):
op.mode = 'FACE_MAPS'
+class VIEW3D_MT_random_mask(Menu):
+ bl_label = "Random Mask"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ op = layout.operator("sculpt.mask_init", text='Per Vertex')
+ op.mode = 'RANDOM_PER_VERTEX'
+
+ op = layout.operator("sculpt.mask_init", text='Per Face Set')
+ op.mode = 'RANDOM_PER_FACE_SET'
+
+ op = layout.operator("sculpt.mask_init", text='Per Loose Part')
+ op.mode = 'RANDOM_PER_LOOSE_PART'
+
class VIEW3D_MT_particle(Menu):
bl_label = "Particle"
@@ -3806,11 +3829,10 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
col.operator("mesh.mark_sharp")
col.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
- if render.use_freestyle:
- col.separator()
+ col.separator()
- col.operator("mesh.mark_freestyle_edge").clear = False
- col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
+ col.operator("mesh.mark_freestyle_edge").clear = False
+ col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
col.separator()
@@ -4005,11 +4027,10 @@ class VIEW3D_MT_edit_mesh_edges_data(Menu):
props.use_verts = True
props.clear = True
- if render.use_freestyle:
- layout.separator()
+ layout.separator()
- layout.operator("mesh.mark_freestyle_edge").clear = False
- layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
+ layout.operator("mesh.mark_freestyle_edge").clear = False
+ layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
class VIEW3D_MT_edit_mesh_edges(Menu):
@@ -4981,7 +5002,7 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.menu("VIEW3D_MT_edit_gpencil_showhide")
- layout.operator_menu_enum("gpencil.stroke_separate", "mode")
+ layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate")
layout.menu("GPENCIL_MT_cleanup")
layout.separator()
@@ -5010,7 +5031,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
layout.menu("GPENCIL_MT_move_to_layer")
layout.menu("VIEW3D_MT_assign_material")
layout.operator("gpencil.set_active_material", text="Set as Active Material")
- layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes")
+ layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange")
layout.separator()
@@ -5021,7 +5042,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
layout.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps", property="type")
layout.operator("gpencil.stroke_flip", text="Switch Direction")
- layout.prop(settings, "use_scale_thickness")
+ layout.prop(settings, "use_scale_thickness", text="Scale Thickness")
layout.separator()
layout.operator("gpencil.reset_transform_fill", text="Reset Fill Transform")
@@ -5033,15 +5054,15 @@ class VIEW3D_MT_edit_gpencil_point(Menu):
def draw(self, _context):
layout = self.layout
- layout.operator("gpencil.extrude_move", text="Extrude Points")
+ layout.operator("gpencil.extrude_move", text="Extrude")
layout.separator()
- layout.operator("gpencil.stroke_smooth", text="Smooth Points").only_selected = True
+ layout.operator("gpencil.stroke_smooth", text="Smooth").only_selected = True
layout.separator()
- layout.operator("gpencil.stroke_merge", text="Merge Points")
+ layout.operator("gpencil.stroke_merge", text="Merge")
# TODO: add new RIP operator
@@ -7009,10 +7030,9 @@ class VIEW3D_PT_gpencil_curve_edit(Panel):
bl_label = "Curve Editing"
def draw(self, context):
- gpd = context.gpencil_data
- settings = context.tool_settings.gpencil_sculpt
-
layout = self.layout
+
+ gpd = context.gpencil_data
col = layout.column(align=True)
col.prop(gpd, "edit_curve_resolution")
col.prop(gpd, "curve_edit_threshold")
@@ -7046,12 +7066,12 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
- col.operator("gpencil.extrude_move", text="Extrude Points")
+ col.operator("gpencil.extrude_move", text="Extrude")
col.separator()
# Deform Operators
- col.operator("gpencil.stroke_smooth", text="Smooth Points").only_selected = True
+ col.operator("gpencil.stroke_smooth", text="Smooth").only_selected = True
col.operator("transform.bend", text="Bend")
col.operator("transform.shear", text="Shear")
col.operator("transform.tosphere", text="To Sphere")
@@ -7059,8 +7079,8 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
- col.menu("VIEW3D_MT_mirror", text="Mirror Points")
- col.menu("GPENCIL_MT_snap", text="Snap Points")
+ col.menu("VIEW3D_MT_mirror", text="Mirror")
+ col.menu("GPENCIL_MT_snap", text="Snap")
col.separator()
@@ -7073,15 +7093,15 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
# Removal Operators
- col.operator("gpencil.stroke_merge", text="Merge Points")
+ col.operator("gpencil.stroke_merge", text="Merge")
col.operator("gpencil.stroke_merge_by_distance").use_unselected = False
col.operator("gpencil.stroke_split", text="Split")
col.operator("gpencil.stroke_separate", text="Separate").mode = 'POINT'
col.separator()
- col.operator("gpencil.delete", text="Delete Points").type = 'POINTS'
- col.operator("gpencil.dissolve", text="Dissolve Points").type = 'POINTS'
+ col.operator("gpencil.delete", text="Delete").type = 'POINTS'
+ col.operator("gpencil.dissolve", text="Dissolve").type = 'POINTS'
col.operator("gpencil.dissolve", text="Dissolve Between").type = 'BETWEEN'
col.operator("gpencil.dissolve", text="Dissolve Unselected").type = 'UNSELECT'
@@ -7098,7 +7118,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
- col.operator("gpencil.stroke_smooth", text="Smooth Stroke").only_selected = False
+ col.operator("gpencil.stroke_smooth", text="Smooth").only_selected = False
col.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.separator()
@@ -7107,12 +7127,12 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.menu("GPENCIL_MT_move_to_layer")
col.menu("VIEW3D_MT_assign_material")
col.operator("gpencil.set_active_material", text="Set as Active Material")
- col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes")
+ col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange")
col.separator()
- col.menu("VIEW3D_MT_mirror", text="Mirror Stroke")
- col.menu("VIEW3D_MT_snap", text="Snap Stroke")
+ col.menu("VIEW3D_MT_mirror", text="Mirror")
+ col.menu("VIEW3D_MT_snap", text="Snap")
col.separator()
@@ -7132,11 +7152,11 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
- col.operator("gpencil.delete", text="Delete Strokes").type = 'STROKES'
+ col.operator("gpencil.delete", text="Delete").type = 'STROKES'
col.separator()
- col.operator("gpencil.reproject", text="Reproject Strokes")
+ col.operator("gpencil.reproject", text="Reproject")
def draw_gpencil_layer_active(context, layout):
@@ -7561,6 +7581,7 @@ classes = (
VIEW3D_MT_mask,
VIEW3D_MT_face_sets,
VIEW3D_MT_face_sets_init,
+ VIEW3D_MT_random_mask,
VIEW3D_MT_particle,
VIEW3D_MT_particle_context_menu,
VIEW3D_MT_particle_showhide,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index a469973c28f..ee8fc1f3531 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -199,8 +199,6 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
ob = context.active_object
mesh = ob.data
- split = layout.split()
-
row = layout.row(align=True, heading="Transform")
row.prop(tool_settings, "use_transform_correct_face_attributes")
@@ -633,10 +631,10 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
settings = self.paint_settings(context)
brush = settings.brush
+ tex_slot = brush.texture_slot
col = layout.column()
-
- col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
+ col.template_ID_preview(tex_slot, "texture", new="texture.new", rows=3, cols=8)
brush_texture_settings(col, brush, context.sculpt_object)
@@ -660,8 +658,9 @@ class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel, TextureMaskPanel):
brush = context.tool_settings.image_paint.brush
col = layout.column()
+ mask_tex_slot = brush.mask_texture_slot
- col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
+ col.template_ID_preview(mask_tex_slot, "texture", new="texture.new", rows=3, cols=8)
brush_mask_texture_settings(col, brush)
@@ -1352,8 +1351,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePenci
if context.mode == 'PAINT_GPENCIL':
brush = tool_settings.gpencil_paint.brush
if brush is not None:
- gp_settings = brush.gpencil_settings
-
col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="")
if brush.use_custom_icon:
@@ -1492,8 +1489,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel):
brush = context.tool_settings.gpencil_paint.brush
return brush is not None and brush.gpencil_tool == 'DRAW'
- def draw(self, context):
- layout = self.layout
+ def draw(self, _context):
+ # layout = self.layout
+ pass
class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(Panel, View3DPanel):
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index ba0a22af0d1..6e1397ff971 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -94,6 +94,11 @@ def node_group_items(context):
yield NodeItemCustom(draw=group_tools_draw)
+ yield NodeItem("NodeGroupInput", poll=group_input_output_item_poll)
+ yield NodeItem("NodeGroupOutput", poll=group_input_output_item_poll)
+
+ yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+
def contains_group(nodetree, group):
if nodetree == group:
return True
@@ -200,7 +205,6 @@ shader_node_categories = [
NodeItem("ShaderNodeUVMap"),
NodeItem("ShaderNodeVertexColor"),
NodeItem("ShaderNodeUVAlongStroke", poll=line_style_shader_nodes_poll),
- NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll),
@@ -208,7 +212,6 @@ shader_node_categories = [
NodeItem("ShaderNodeOutputAOV"),
NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll),
NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll),
- NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
]),
ShaderNodeCategory("SH_NEW_SHADER", "Shader", items=[
NodeItem("ShaderNodeMixShader", poll=eevee_cycles_shader_nodes_poll),
@@ -310,7 +313,6 @@ compositor_node_categories = [
NodeItem("CompositorNodeBokehImage"),
NodeItem("CompositorNodeTime"),
NodeItem("CompositorNodeTrackPos"),
- NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
CompositorNodeCategory("CMP_OUTPUT", "Output", items=[
NodeItem("CompositorNodeComposite"),
@@ -318,7 +320,6 @@ compositor_node_categories = [
NodeItem("CompositorNodeSplitViewer"),
NodeItem("CompositorNodeOutputFile"),
NodeItem("CompositorNodeLevels"),
- NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
]),
CompositorNodeCategory("CMP_OP_COLOR", "Color", items=[
NodeItem("CompositorNodeMixRGB"),
@@ -389,6 +390,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeColorMatte"),
NodeItem("CompositorNodeDoubleEdgeMask"),
NodeItem("CompositorNodeCryptomatte"),
+ NodeItem("CompositorNodeCryptomatteV2"),
]),
CompositorNodeCategory("CMP_DISTORT", "Distort", items=[
NodeItem("CompositorNodeScale"),
@@ -420,12 +422,10 @@ texture_node_categories = [
NodeItem("TextureNodeCoordinates"),
NodeItem("TextureNodeTexture"),
NodeItem("TextureNodeImage"),
- NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
TextureNodeCategory("TEX_OUTPUT", "Output", items=[
NodeItem("TextureNodeOutput"),
NodeItem("TextureNodeViewer"),
- NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
]),
TextureNodeCategory("TEX_OP_COLOR", "Color", items=[
NodeItem("TextureNodeMixRGB"),
@@ -485,6 +485,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeCompare"),
+ NodeItem("GeometryNodeAttributeConvert"),
NodeItem("GeometryNodeAttributeFill"),
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeProximity"),
@@ -493,6 +494,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeSampleTexture"),
NodeItem("GeometryNodeAttributeCombineXYZ"),
NodeItem("GeometryNodeAttributeSeparateXYZ"),
+ NodeItem("GeometryNodeAttributeRemove"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),
@@ -517,7 +519,17 @@ geometry_node_categories = [
NodeItem("GeometryNodeTriangulate"),
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeSubdivisionSurface"),
- NodeItem("GeometryNodeSubdivisionSurfaceSimple"),
+ NodeItem("GeometryNodeSubdivide"),
+
+ # These should be in a sub-menu, but that requires a refactor to build the add menu manually.
+ NodeItem("GeometryNodeMeshCube"),
+ NodeItem("GeometryNodeMeshCircle"),
+ NodeItem("GeometryNodeMeshUVSphere"),
+ NodeItem("GeometryNodeMeshIcoSphere"),
+ NodeItem("GeometryNodeMeshCylinder"),
+ NodeItem("GeometryNodeMeshCone"),
+ NodeItem("GeometryNodeMeshLine"),
+ NodeItem("GeometryNodeMeshPlane"),
]),
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),
@@ -543,6 +555,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeSeparateXYZ"),
NodeItem("ShaderNodeCombineXYZ"),
NodeItem("ShaderNodeVectorMath"),
+ NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index f875a990d0a..8d18cf0ae9a 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_layer_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lineart_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_listBase.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mask_types.h
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 8666291cec8..d43332ae1ac 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -266,7 +266,7 @@ void BKE_animsys_evaluate_all_animation(struct Main *main,
void animsys_evaluate_action(struct PointerRNA *ptr,
struct bAction *act,
const struct AnimationEvalContext *anim_eval_context,
- const bool flush_to_original);
+ bool flush_to_original);
/* Evaluate Action Group */
void animsys_evaluate_action_group(struct PointerRNA *ptr,
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index db44a771095..f5face2120e 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -27,6 +27,8 @@
extern "C" {
#endif
+struct AnimationEvalContext;
+struct bAction;
struct BMEditMesh;
struct Bone;
struct Depsgraph;
@@ -193,6 +195,12 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
bool do_extra);
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
+/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
+ * relate to those bones are evaluated. */
+void BKE_pose_apply_action(struct Object *ob,
+ struct bAction *action,
+ struct AnimationEvalContext *anim_eval_context);
+
/* get_objectspace_bone_matrix has to be removed still */
void get_objectspace_bone_matrix(struct Bone *bone,
float M_accumulatedMatrix[4][4],
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 574d9904dc4..a98bfd1e3df 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -39,6 +39,7 @@ struct ReportList;
/* Attribute.domain */
typedef enum AttributeDomain {
+ ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 17eb6e19292..eb5f910f555 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 9
+#define BLENDER_FILE_SUBVERSION 13
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index f73c4a70809..429e294a337 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -23,6 +23,7 @@
extern "C" {
#endif
+struct BlendFileData;
struct BlendFileReadParams;
struct ID;
struct Main;
@@ -31,36 +32,32 @@ struct ReportList;
struct UserDef;
struct bContext;
-bool BKE_blendfile_read_ex(struct bContext *C,
- const char *filepath,
- const struct BlendFileReadParams *params,
- struct ReportList *reports,
- /* Extra args. */
- const bool startup_update_defaults,
- const char *startup_app_template);
-bool BKE_blendfile_read(struct bContext *C,
- const char *filepath,
- const struct BlendFileReadParams *params,
- struct ReportList *reports);
+void BKE_blendfile_read_setup_ex(struct bContext *C,
+ struct BlendFileData *bfd,
+ const struct BlendFileReadParams *params,
+ struct ReportList *reports,
+ /* Extra args. */
+ const bool startup_update_defaults,
+ const char *startup_app_template);
-bool BKE_blendfile_read_from_memory_ex(struct bContext *C,
- const void *filebuf,
- int filelength,
- const struct BlendFileReadParams *params,
- struct ReportList *reports,
- /* Extra args. */
- const bool startup_update_defaults,
- const char *startup_app_template);
-bool BKE_blendfile_read_from_memory(struct bContext *C,
- const void *filebuf,
- int filelength,
- const struct BlendFileReadParams *params,
- struct ReportList *reports);
+void BKE_blendfile_read_setup(struct bContext *C,
+ struct BlendFileData *bfd,
+ const struct BlendFileReadParams *params,
+ struct ReportList *reports);
-bool BKE_blendfile_read_from_memfile(struct bContext *C,
- struct MemFile *memfile,
- const struct BlendFileReadParams *params,
- struct ReportList *reports);
+struct BlendFileData *BKE_blendfile_read(const char *filepath,
+ const struct BlendFileReadParams *params,
+ struct ReportList *reports);
+
+struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
+ int filelength,
+ const struct BlendFileReadParams *params,
+ struct ReportList *reports);
+
+struct BlendFileData *BKE_blendfile_read_from_memfile(struct Main *bmain,
+ struct MemFile *memfile,
+ const struct BlendFileReadParams *params,
+ struct ReportList *reports);
void BKE_blendfile_read_make_empty(struct bContext *C);
struct UserDef *BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports);
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index d15aebfe03d..d0fca5e3796 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -82,6 +82,8 @@ struct Collection *BKE_collection_master_add(void);
bool BKE_collection_has_object(struct Collection *collection, const struct Object *ob);
bool BKE_collection_has_object_recursive(struct Collection *collection, struct Object *ob);
+bool BKE_collection_has_object_recursive_instanced(struct Collection *collection,
+ struct Object *ob);
struct Collection *BKE_collection_object_find(struct Main *bmain,
struct Scene *scene,
struct Collection *collection,
@@ -123,6 +125,7 @@ bool BKE_collection_object_cyclic_check(struct Main *bmain,
/* Object list cache. */
struct ListBase BKE_collection_object_cache_get(struct Collection *collection);
+ListBase BKE_collection_object_cache_instanced_get(struct Collection *collection);
void BKE_collection_object_cache_free(struct Collection *collection);
struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer,
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 94392dd78da..3d30188e517 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -197,6 +197,7 @@ struct SpaceInfo *CTX_wm_space_info(const bContext *C);
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C);
struct SpaceClip *CTX_wm_space_clip(const bContext *C);
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
+struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 96e853e7ff8..576a2c1effd 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -30,16 +30,17 @@
extern "C" {
#endif
+/* Forward declarations. */
struct CryptomatteSession;
-struct ID;
-struct Main;
struct Material;
struct Object;
struct RenderResult;
+struct Scene;
struct CryptomatteSession *BKE_cryptomatte_init(void);
struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
const struct RenderResult *render_result);
+struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene);
void BKE_cryptomatte_free(struct CryptomatteSession *session);
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name);
@@ -54,6 +55,10 @@ uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
+bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
+ const float encoded_hash,
+ char *r_name,
+ int name_len);
char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage);
void BKE_cryptomatte_matte_id_to_entries(struct NodeCryptomatte *node_storage,
@@ -65,4 +70,4 @@ void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session,
#ifdef __cplusplus
}
-#endif
+#endif \ No newline at end of file
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index f10b4c1f7c4..9e205d01765 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -26,9 +26,13 @@
#include <optional>
#include <string>
+#include "BKE_cryptomatte.h"
+
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
+#include "BKE_cryptomatte.h"
+
struct ID;
namespace blender::bke::cryptomatte {
@@ -103,4 +107,16 @@ struct CryptomatteStampDataCallbackData {
static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len);
};
+const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
+ const CryptomatteSession &session);
+
+struct CryptomatteSessionDeleter {
+ void operator()(CryptomatteSession *session)
+ {
+ BKE_cryptomatte_free(session);
+ }
+};
+
+using CryptomatteSessionPtr = std::unique_ptr<CryptomatteSession, CryptomatteSessionDeleter>;
+
} // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h
index ac42674654f..08b4a25d946 100644
--- a/source/blender/blenkernel/BKE_geometry_set.h
+++ b/source/blender/blenkernel/BKE_geometry_set.h
@@ -28,6 +28,16 @@ struct Collection;
struct GeometrySet;
struct Object;
+/* Each geometry component has a specific type. The type determines what kind of data the component
+ * stores. Functions modifying a geometry will usually just modify a subset of the component types.
+ */
+typedef enum GeometryComponentType {
+ GEO_COMPONENT_TYPE_MESH = 0,
+ GEO_COMPONENT_TYPE_POINT_CLOUD = 1,
+ GEO_COMPONENT_TYPE_INSTANCES = 2,
+ GEO_COMPONENT_TYPE_VOLUME = 3,
+} GeometryComponentType;
+
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index ad01814ce82..8cc37a3e711 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -40,16 +40,6 @@ struct Object;
struct PointCloud;
struct Volume;
-/* Each geometry component has a specific type. The type determines what kind of data the component
- * stores. Functions modifying a geometry will usually just modify a subset of the component types.
- */
-enum class GeometryComponentType {
- Mesh = 0,
- PointCloud = 1,
- Instances = 2,
- Volume = 3,
-};
-
enum class GeometryOwnershipType {
/* The geometry is owned. This implies that it can be changed. */
Owned = 0,
@@ -59,16 +49,6 @@ enum class GeometryOwnershipType {
ReadOnly = 2,
};
-/* Make it possible to use the component type as key in hash tables. */
-namespace blender {
-template<> struct DefaultHash<GeometryComponentType> {
- uint64_t operator()(const GeometryComponentType &value) const
- {
- return (uint64_t)value;
- }
-};
-} // namespace blender
-
namespace blender::bke {
class ComponentAttributeProviders;
}
@@ -392,7 +372,7 @@ class MeshComponent : public GeometryComponent {
bool is_empty() const final;
- static constexpr inline GeometryComponentType static_type = GeometryComponentType::Mesh;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
@@ -422,7 +402,7 @@ class PointCloudComponent : public GeometryComponent {
bool is_empty() const final;
- static constexpr inline GeometryComponentType static_type = GeometryComponentType::PointCloud;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
@@ -462,7 +442,7 @@ class InstancesComponent : public GeometryComponent {
bool is_empty() const final;
- static constexpr inline GeometryComponentType static_type = GeometryComponentType::Instances;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
};
/** A geometry component that stores volume grids. */
@@ -484,5 +464,5 @@ class VolumeComponent : public GeometryComponent {
const Volume *get_for_read() const;
Volume *get_for_write();
- static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME;
};
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index d6b6ffd425e..9e237679795 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -77,6 +77,7 @@ typedef struct Global {
* * 1112: Disable new Cloth internal springs handling (09/2014).
* * 1234: Disable new dyntopo code fixing skinny faces generation (04/2015).
* * 3001: Enable additional Fluid modifier (Mantaflow) options (02/2020).
+ * * 4000: Line Art state output and debugging logs (03/2021).
* * 16384 and above: Reserved for python (add-ons) usage.
*/
short debug_value;
@@ -170,9 +171,23 @@ enum {
/* Bits 11 to 22 (inclusive) are deprecated & need to be cleared */
- /** On read, use #FileGlobal.filename instead of the real location on-disk,
- * needed for recovering temp files so relative paths resolve */
- G_FILE_RECOVER = (1 << 23),
+ /**
+ * On read, use #FileGlobal.filename instead of the real location on-disk,
+ * needed for recovering temp files so relative paths resolve.
+ *
+ * \note In some ways it would be nicer to make this an argument passed to file loading.
+ * In practice this means recover needs to be passed around to too many low level functions,
+ * so keep this as a flag.
+ */
+ G_FILE_RECOVER_READ = (1 << 23),
+ /**
+ * On write, assign use #FileGlobal.filename, otherwise leave it blank,
+ * needed so files can be recovered at their original locations.
+ *
+ * \note only #BLENDER_QUIT_FILE and auto-save files include recovery information.
+ * As users/developers may not want their paths exposed in publicly distributed files.
+ */
+ G_FILE_RECOVER_WRITE = (1 << 24),
/** BMesh option to save as older mesh format */
/* #define G_FILE_MESH_COMPAT (1 << 26) */
/* #define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28) */ /* deprecated */
@@ -182,7 +197,7 @@ enum {
* Run-time only #G.fileflags which are never read or written to/from Blend files.
* This means we can change the values without worrying about do-versions.
*/
-#define G_FILE_FLAG_ALL_RUNTIME (G_FILE_NO_UI)
+#define G_FILE_FLAG_ALL_RUNTIME (G_FILE_NO_UI | G_FILE_RECOVER_READ | G_FILE_RECOVER_WRITE)
/** ENDIAN_ORDER: indicates what endianness the platform where the file was written had. */
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 5cfdcf241d1..a0a3f30d6d8 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -212,6 +212,10 @@ void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl);
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd);
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames);
+struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
+ char *name,
+ int first_if_not_found);
+
/* Brush */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
@@ -231,6 +235,7 @@ struct Material *BKE_gpencil_object_material_new(struct Main *bmain,
int *r_index);
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma);
+int BKE_gpencil_object_material_get_index_name(struct Object *ob, char *name);
struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob,
struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index c066c161f46..c6406c8478c 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -206,7 +206,8 @@ typedef struct GpencilModifierTypeInfo {
* This function is optional.
*/
void (*updateDepsgraph)(struct GpencilModifierData *md,
- const struct ModifierUpdateDepsgraphContext *ctx);
+ const struct ModifierUpdateDepsgraphContext *ctx,
+ const int mode);
/**
* Should return true if the modifier needs to be recalculated on time
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 5fd451dc986..e0cb2d9abb0 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -50,6 +50,7 @@ struct Main;
struct Object;
struct PointerRNA;
struct PropertyRNA;
+struct ReportList;
struct Scene;
struct ViewLayer;
@@ -61,6 +62,8 @@ void BKE_lib_override_library_copy(struct ID *dst_id,
void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user);
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
+bool BKE_lib_override_library_is_user_edited(struct ID *id);
+
struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
const bool do_tagged_remap);
@@ -77,7 +80,12 @@ bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
- struct ID *id_root);
+ struct ID *id_root,
+ const bool do_hierarchy_enforce);
+void BKE_lib_override_library_main_resync(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
@@ -122,6 +130,11 @@ bool BKE_lib_override_library_property_operation_operands_validate(
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage);
+void BKE_lib_override_library_validate(struct Main *bmain,
+ struct ID *id,
+ struct ReportList *reports);
+void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports);
+
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index f064d03261d..4e781aea9d3 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -71,6 +71,13 @@ enum {
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5),
/**
+ * Indicates that this is an internal runtime ID pointer, like e.g. `ID.newid` or `ID.original`.
+ * \note Those should be ignored in most cases, and won't be processed/generated anyway unless
+ * `IDWALK_DO_INTERNAL_RUNTIME_POINTERS` option is enabled.
+ */
+ IDWALK_CB_INTERNAL = (1 << 6),
+
+ /**
* This ID usage is fully refcounted.
* Callback is responsible to deal accordingly with #ID.us if needed.
*/
@@ -126,6 +133,9 @@ enum {
IDWALK_IGNORE_EMBEDDED_ID = (1 << 3),
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
+ /** Also process internal ID pointers like `ID.newid` or `ID.orig_id`.
+ * WARNING: Dangerous, use with caution. */
+ IDWALK_DO_INTERNAL_RUNTIME_POINTERS = (1 << 9),
};
typedef struct LibraryForeachIDData LibraryForeachIDData;
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index a8d75213d39..705d2b030e5 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -76,6 +76,15 @@ enum {
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
/** Do not remap library override pointers. */
ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5,
+ /** Don't touch the user count (use for low level actions such as swapping pointers). */
+ ID_REMAP_SKIP_USER_CLEAR = 1 << 6,
+ /**
+ * Force internal ID runtime pointers (like `ID.newid`, `ID.orig_id` etc.) to also be processed.
+ * This should only be needed in some very specific cases, typically only BKE ID management code
+ * should need it (e.g. required from `id_delete` to ensure no runtime pointer remains using
+ * freed ones).
+ */
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS = 1 << 7,
};
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately,
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index b6116b32ca5..2c6e5ed3873 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -223,7 +223,7 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb) \
{ \
- ListBase *_lbarray[MAX_LIBARRAY]; \
+ ListBase *_lbarray[INDEX_ID_MAX]; \
int _i = set_listbasepointers((_bmain), _lbarray); \
while (_i--) { \
(_lb) = _lbarray[_i];
@@ -234,9 +234,13 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
((void)0)
/**
- * DO NOT use break statement with that macro,
- * use #FOREACH_MAIN_LISTBASE and #FOREACH_MAIN_LISTBASE_ID instead
- * if you need that kind of control flow. */
+ * Top level `foreach`-like macro allowing to loop over all IDs in a given #Main data-base.
+ *
+ * NOTE: Order tries to go from 'user IDs' to 'used IDs' (e.g. collections will be processed
+ * before objects, which will be processed before obdata types, etc.).
+ *
+ * WARNING: DO NOT use break statement with that macro, use #FOREACH_MAIN_LISTBASE and
+ * #FOREACH_MAIN_LISTBASE_ID instead if you need that kind of control flow. */
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id) \
{ \
ListBase *_lb; \
@@ -259,8 +263,8 @@ const char *BKE_main_blendfile_path_from_global(void);
struct ListBase *which_libbase(struct Main *bmain, short type);
-#define MAX_LIBARRAY 41
-int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
+//#define INDEX_ID_MAX 41
+int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
((main)->versionfile > (ver) || \
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.h b/source/blender/blenkernel/BKE_mesh_boolean_convert.h
index be5cbb305fa..1bb1d9ea8dc 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.h
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.h
@@ -29,8 +29,10 @@ extern "C" {
Mesh *BKE_mesh_boolean(const Mesh **meshes,
const float (*obmats[])[4][4],
+ const short **material_remaps,
const int meshes_len,
const bool use_self,
+ const bool hole_tolerant,
const int boolean_mode);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h
index a91f0787e68..7b230b04410 100644
--- a/source/blender/blenkernel/BKE_mesh_mirror.h
+++ b/source/blender/blenkernel/BKE_mesh_mirror.h
@@ -46,7 +46,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd,
struct Object *ob,
const struct Mesh *mesh,
- int axis);
+ const int axis);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d675df6d868..013c90197b2 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -47,6 +47,7 @@ struct BlendLibReader;
struct BlendWriter;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct CryptomatteSession;
struct FreestyleLineStyle;
struct GPUMaterial;
struct GPUNodeStack;
@@ -301,11 +302,11 @@ typedef struct bNodeType {
void (*free_self)(struct bNodeType *ntype);
/* **** execution callbacks **** */
- NodeInitExecFunction initexecfunc;
- NodeFreeExecFunction freeexecfunc;
- NodeExecFunction execfunc;
+ NodeInitExecFunction init_exec_fn;
+ NodeFreeExecFunction free_exec_fn;
+ NodeExecFunction exec_fn;
/* gpu */
- NodeGPUExecFunction gpufunc;
+ NodeGPUExecFunction gpu_fn;
/* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
NodeExpandInMFNetworkFunction expand_in_mf_network;
@@ -626,6 +627,7 @@ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNodeSocket *tosock);
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
+void nodeMuteLinkToggle(struct bNodeTree *ntree, struct bNodeLink *link);
bool nodeLinkIsHidden(const struct bNodeLink *link);
void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node);
@@ -829,10 +831,10 @@ void node_type_group_update(struct bNodeType *ntype,
struct bNode *node));
void node_type_exec(struct bNodeType *ntype,
- NodeInitExecFunction initexecfunc,
- NodeFreeExecFunction freeexecfunc,
- NodeExecFunction execfunc);
-void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc);
+ NodeInitExecFunction init_exec_fn,
+ NodeFreeExecFunction free_exec_fn,
+ NodeExecFunction exec_fn);
+void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn);
void node_type_internal_links(struct bNodeType *ntype,
void (*update_internal_links)(struct bNodeTree *, struct bNode *));
@@ -1204,9 +1206,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
#define CMP_NODE_SWITCH_VIEW 322
-#define CMP_NODE_CRYPTOMATTE 323
+#define CMP_NODE_CRYPTOMATTE_LEGACY 323
#define CMP_NODE_DENOISE 324
#define CMP_NODE_EXPOSURE 325
+#define CMP_NODE_CRYPTOMATTE 326
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1236,6 +1239,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_TRACKPOS_RELATIVE_FRAME 2
#define CMP_TRACKPOS_ABSOLUTE_FRAME 3
+/* Cryptomatte source. */
+#define CMP_CRYPTOMATTE_SRC_RENDER 0
+#define CMP_CRYPTOMATTE_SRC_IMAGE 1
+
/* API */
void ntreeCompositExecTree(struct Scene *scene,
struct bNodeTree *ntree,
@@ -1278,10 +1285,15 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *ntree, bNode *node);
-struct bNodeSocket *ntreeCompositCryptomatteAddSocket(struct bNodeTree *ntree, struct bNode *node);
-int ntreeCompositCryptomatteRemoveSocket(struct bNodeTree *ntree, struct bNode *node);
+void ntreeCompositCryptomatteSyncFromAdd(bNode *node);
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
+void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len);
+/* Update the runtime layer names with the cryptomatte layer names of the references
+ * render layer or image. */
+void ntreeCompositCryptomatteUpdateLayerNames(bNode *node);
+struct CryptomatteSession *ntreeCompositCryptomatteSession(bNode *node);
/** \} */
@@ -1371,7 +1383,17 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_VOLUME_TO_MESH 1026
#define GEO_NODE_ATTRIBUTE_COMBINE_XYZ 1027
#define GEO_NODE_ATTRIBUTE_SEPARATE_XYZ 1028
-#define GEO_NODE_SUBDIVISION_SURFACE_SIMPLE 1029
+#define GEO_NODE_SUBDIVIDE 1029
+#define GEO_NODE_ATTRIBUTE_REMOVE 1030
+#define GEO_NODE_ATTRIBUTE_CONVERT 1031
+#define GEO_NODE_MESH_PRIMITIVE_CUBE 1032
+#define GEO_NODE_MESH_PRIMITIVE_CIRCLE 1033
+#define GEO_NODE_MESH_PRIMITIVE_UV_SPHERE 1034
+#define GEO_NODE_MESH_PRIMITIVE_CYLINDER 1035
+#define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE 1036
+#define GEO_NODE_MESH_PRIMITIVE_CONE 1037
+#define GEO_NODE_MESH_PRIMITIVE_LINE 1038
+#define GEO_NODE_MESH_PRIMITIVE_PLANE 1039
/** \} */
diff --git a/source/blender/blenkernel/BKE_node_ui_storage.hh b/source/blender/blenkernel/BKE_node_ui_storage.hh
index a49ff988272..be9510179c3 100644
--- a/source/blender/blenkernel/BKE_node_ui_storage.hh
+++ b/source/blender/blenkernel/BKE_node_ui_storage.hh
@@ -20,13 +20,17 @@
#include "BLI_hash.hh"
#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
#include "BLI_session_uuid.h"
#include "BLI_set.hh"
#include "DNA_ID.h"
+#include "DNA_customdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_session_uuid_types.h"
+#include "BKE_attribute.h"
+
struct ModifierData;
struct Object;
struct bNode;
@@ -77,9 +81,26 @@ struct NodeWarning {
std::string message;
};
+struct AvailableAttributeInfo {
+ AttributeDomain domain;
+ CustomDataType data_type;
+
+ uint64_t hash() const
+ {
+ uint64_t domain_hash = (uint64_t)domain;
+ uint64_t data_type_hash = (uint64_t)data_type;
+ return (domain_hash * 33) ^ (data_type_hash * 89);
+ }
+
+ friend bool operator==(const AvailableAttributeInfo &a, const AvailableAttributeInfo &b)
+ {
+ return a.domain == b.domain && a.data_type == b.data_type;
+ }
+};
+
struct NodeUIStorage {
blender::Vector<NodeWarning> warnings;
- blender::Set<std::string> attribute_name_hints;
+ blender::MultiValueMap<std::string, AvailableAttributeInfo> attribute_hints;
};
struct NodeTreeUIStorage {
@@ -103,4 +124,6 @@ void BKE_nodetree_error_message_add(bNodeTree &ntree,
void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
const NodeTreeEvaluationContext &context,
const bNode &node,
- const blender::StringRef attribute_name);
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type);
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index 1ec8a8e84cd..1f6e89636c4 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -21,7 +21,6 @@
#endif
struct Mesh;
-struct VolumeGrid;
namespace blender::bke {
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1e7986eedd9..310ac6c4903 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -77,6 +77,7 @@ set(SRC
intern/appdir.c
intern/armature.c
intern/armature_deform.c
+ intern/armature_pose.cc
intern/armature_update.c
intern/asset.cc
intern/attribute.c
@@ -130,6 +131,10 @@ set(SRC
intern/fmodifier.c
intern/font.c
intern/freestyle.c
+ intern/geometry_component_instances.cc
+ intern/geometry_component_mesh.cc
+ intern/geometry_component_pointcloud.cc
+ intern/geometry_component_volume.cc
intern/geometry_set.cc
intern/geometry_set_instances.cc
intern/gpencil.c
@@ -429,6 +434,7 @@ set(SRC
nla_private.h
particle_private.h
tracking_private.h
+ intern/attribute_access_intern.hh
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc
new file mode 100644
index 00000000000..bb371b16c42
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature_pose.cc
@@ -0,0 +1,133 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Defines and code for core node types
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+
+#include "BLI_set.hh"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "RNA_access.h"
+
+namespace {
+using BoneNameSet = blender::Set<std::string>;
+
+// Forward declarations.
+BoneNameSet pose_apply_find_selected_bones(const bPose *pose);
+void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
+ const BoneNameSet &selected_bone_names);
+void pose_apply_restore_fcurves(bAction *action);
+} // namespace
+
+void BKE_pose_apply_action(struct Object *ob,
+ struct bAction *action,
+ struct AnimationEvalContext *anim_eval_context)
+{
+ bPose *pose = ob->pose;
+ if (pose == nullptr) {
+ return;
+ }
+
+ const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose);
+ const bool limit_to_selected_bones = !selected_bone_names.is_empty();
+
+ if (limit_to_selected_bones) {
+ /* Mute all FCurves that are not associated with selected bones. This separates the concept of
+ * bone selection from the FCurve evaluation code. */
+ pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names);
+ }
+
+ /* Apply the Action. */
+ PointerRNA pose_owner_ptr;
+ RNA_id_pointer_create(&ob->id, &pose_owner_ptr);
+ animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false);
+
+ if (limit_to_selected_bones) {
+ pose_apply_restore_fcurves(action);
+ }
+}
+
+namespace {
+BoneNameSet pose_apply_find_selected_bones(const bPose *pose)
+{
+ BoneNameSet selected_bone_names;
+ bool all_bones_selected = true;
+ bool no_bones_selected = true;
+
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
+ const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 &&
+ (pchan->bone->flag & BONE_HIDDEN_P) == 0;
+ all_bones_selected &= is_selected;
+ no_bones_selected &= !is_selected;
+
+ if (is_selected) {
+ /* Bone names are unique, so no need to check for duplicates. */
+ selected_bone_names.add_new(pchan->name);
+ }
+ }
+
+ /* If no bones are selected, act as if all are. */
+ if (all_bones_selected || no_bones_selected) {
+ return BoneNameSet(); /* An empty set means "ignore bone selection". */
+ }
+ return selected_bone_names;
+}
+
+void pose_apply_restore_fcurves(bAction *action)
+{
+ /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */
+ LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
+ fcu->flag &= ~FCURVE_DISABLED;
+ }
+}
+
+void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
+ const BoneNameSet &selected_bone_names)
+{
+ LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
+ if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) {
+ continue;
+ }
+
+ /* Get bone name, and check if this bone is selected. */
+ char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ if (!bone_name) {
+ continue;
+ }
+ const bool is_selected = selected_bone_names.contains(bone_name);
+ MEM_freeN(bone_name);
+ if (is_selected) {
+ continue;
+ }
+
+ fcu->flag |= FCURVE_DISABLED;
+ }
+}
+
+} // namespace
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index aeb7fba47e8..91b5b01e3eb 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -36,6 +36,8 @@
#include "NOD_node_tree_multi_function.hh"
+#include "attribute_access_intern.hh"
+
static CLG_LogRef LOG = {"bke.attribute_access"};
using blender::float3;
@@ -46,9 +48,6 @@ using blender::bke::ReadAttributePtr;
using blender::bke::WriteAttributePtr;
using blender::fn::GMutableSpan;
-/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
-extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
-
namespace blender::bke {
/* -------------------------------------------------------------------- */
@@ -158,101 +157,6 @@ void WriteAttribute::apply_span_if_necessary()
}
}
-class VertexWeightWriteAttribute final : public WriteAttribute {
- private:
- MDeformVert *dverts_;
- const int dvert_index_;
-
- public:
- VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
- : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- get_internal(dverts_, dvert_index_, index, r_value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = *reinterpret_cast<const float *>(value);
- }
-
- static void get_internal(const MDeformVert *dverts,
- const int dvert_index,
- const int64_t index,
- void *r_value)
- {
- if (dverts == nullptr) {
- *(float *)r_value = 0.0f;
- return;
- }
- const MDeformVert &dvert = dverts[index];
- for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
- if (weight.def_nr == dvert_index) {
- *(float *)r_value = weight.weight;
- return;
- }
- }
- *(float *)r_value = 0.0f;
- }
-};
-
-class VertexWeightReadAttribute final : public ReadAttribute {
- private:
- const MDeformVert *dverts_;
- const int dvert_index_;
-
- public:
- VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
- }
-};
-
-template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<T> data_;
-
- public:
- ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
- : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- data_[index] = *reinterpret_cast<const T *>(value);
- }
-
- void initialize_span(const bool UNUSED(write_only)) override
- {
- array_buffer_ = data_.data();
- array_is_temporary_ = false;
- }
-
- void apply_span_if_necessary() override
- {
- /* Do nothing, because the span contains the attribute itself already. */
- }
-};
-
/* This is used by the #OutputAttributePtr class. */
class TemporaryWriteAttribute final : public WriteAttribute {
public:
@@ -301,135 +205,6 @@ class TemporaryWriteAttribute final : public WriteAttribute {
}
};
-template<typename T> class ArrayReadAttribute final : public ReadAttribute {
- private:
- Span<T> data_;
-
- public:
- ArrayReadAttribute(AttributeDomain domain, Span<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
- private:
- Array<T> data_;
-
- public:
- OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, const ElemT &)>
-class DerivedArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<StructT> data_;
-
- public:
- DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
- : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- StructT &struct_value = data_[index];
- const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
- SetFunc(struct_value, typed_value);
- }
-};
-
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class DerivedArrayReadAttribute final : public ReadAttribute {
- private:
- Span<StructT> data_;
-
- public:
- DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
- : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-};
-
-class ConstantReadAttribute final : public ReadAttribute {
- private:
- void *value_;
-
- public:
- ConstantReadAttribute(AttributeDomain domain,
- const int64_t size,
- const CPPType &type,
- const void *value)
- : ReadAttribute(domain, type, size)
- {
- value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
- type.copy_to_uninitialized(value, value_);
- }
-
- ~ConstantReadAttribute() override
- {
- this->cpp_type_.destruct(value_);
- MEM_freeN(value_);
- }
-
- void get_internal(const int64_t UNUSED(index), void *r_value) const override
- {
- this->cpp_type_.copy_to_uninitialized(value_, r_value);
- }
-
- void initialize_span() const override
- {
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
- }
-};
-
class ConvertedReadAttribute final : public ReadAttribute {
private:
const CPPType &from_type_;
@@ -437,9 +212,6 @@ class ConvertedReadAttribute final : public ReadAttribute {
ReadAttributePtr base_attribute_;
const nodes::DataTypeConversions &conversions_;
- static constexpr int MaxValueSize = 64;
- static constexpr int MaxValueAlignment = 64;
-
public:
ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
: ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
@@ -448,17 +220,13 @@ class ConvertedReadAttribute final : public ReadAttribute {
base_attribute_(std::move(base_attribute)),
conversions_(nodes::get_implicit_type_conversions())
{
- if (from_type_.size() > MaxValueSize || from_type_.alignment() > MaxValueAlignment) {
- throw std::runtime_error(
- "type is larger than expected, the buffer size has to be increased");
- }
}
void get_internal(const int64_t index, void *r_value) const override
{
- AlignedBuffer<MaxValueSize, MaxValueAlignment> buffer;
- base_attribute_->get(index, buffer.ptr());
- conversions_.convert(from_type_, to_type_, buffer.ptr(), r_value);
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ base_attribute_->get(index, buffer);
+ conversions_.convert(from_type_, to_type_, buffer, r_value);
}
};
@@ -598,964 +366,318 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
-/**
- * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component.
- * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do
- * not follow the same loose rules as other attributes, because they are mapped to internal
- * "legacy" data structures. For example, some builtin attributes cannot be deleted. */
-class BuiltinAttributeProvider {
- public:
- /* Some utility enums to avoid hard to read booleans in function calls. */
- enum CreatableEnum {
- Creatable,
- NonCreatable,
- };
- enum WritableEnum {
- Writable,
- Readonly,
- };
- enum DeletableEnum {
- Deletable,
- NonDeletable,
- };
-
- protected:
- const std::string name_;
- const AttributeDomain domain_;
- const CustomDataType data_type_;
- const CreatableEnum createable_;
- const WritableEnum writable_;
- const DeletableEnum deletable_;
-
- public:
- BuiltinAttributeProvider(std::string name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const CreatableEnum createable,
- const WritableEnum writable,
- const DeletableEnum deletable)
- : name_(std::move(name)),
- domain_(domain),
- data_type_(data_type),
- createable_(createable),
- writable_(writable),
- deletable_(deletable)
- {
- }
-
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
- virtual bool try_delete(GeometryComponent &component) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
- virtual bool exists(const GeometryComponent &component) const = 0;
-
- StringRefNull name() const
- {
- return name_;
+ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
+ const GeometryComponent &component) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
- AttributeDomain domain() const
- {
- return domain_;
+ const int domain_size = component.attribute_domain_size(domain_);
+ const void *data = CustomData_get_layer(custom_data, stored_type_);
+ if (data == nullptr) {
+ return {};
}
+ return as_read_attribute_(data, domain_size);
+}
- CustomDataType data_type() const
- {
- return data_type_;
+WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write(
+ GeometryComponent &component) const
+{
+ if (writable_ != Writable) {
+ return {};
}
-};
-
-/**
- * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each
- * attribute has a name, domain and type.
- */
-class DynamicAttributesProvider {
- public:
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const = 0;
- virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component),
- const StringRef UNUSED(attribute_name),
- const AttributeDomain UNUSED(domain),
- const CustomDataType UNUSED(data_type)) const
- {
- /* Some providers should not create new attributes. */
- return false;
- };
-
- virtual bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const = 0;
- virtual void supported_domains(Vector<AttributeDomain> &r_domains) const = 0;
-};
-
-/**
- * Utility to group together multiple functions that are used to access custom data on geometry
- * components in a generic way.
- */
-struct CustomDataAccessInfo {
- using CustomDataGetter = CustomData *(*)(GeometryComponent &component);
- using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component);
- using UpdateCustomDataPointers = void (*)(GeometryComponent &component);
-
- CustomDataGetter get_custom_data;
- ConstCustomDataGetter get_const_custom_data;
- UpdateCustomDataPointers update_custom_data_pointers;
-};
-
-/**
- * This provider is used to provide access to builtin attributes. It supports making internal types
- * available as different types. For example, the vertex position attribute is stored as part of
- * the #MVert struct, but is exposed as float3 attribute.
- */
-class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
- using UpdateOnWrite = void (*)(GeometryComponent &component);
- const CustomDataType stored_type_;
- const CustomDataAccessInfo custom_data_access_;
- const AsReadAttribute as_read_attribute_;
- const AsWriteAttribute as_write_attribute_;
- const UpdateOnWrite update_on_write_;
-
- public:
- BuiltinCustomDataLayerProvider(std::string attribute_name,
- const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
- const CreatableEnum creatable,
- const WritableEnum writable,
- const DeletableEnum deletable,
- const CustomDataAccessInfo custom_data_access,
- const AsReadAttribute as_read_attribute,
- const AsWriteAttribute as_write_attribute,
- const UpdateOnWrite update_on_write)
- : BuiltinAttributeProvider(
- std::move(attribute_name), domain, attribute_type, creatable, writable, deletable),
- stored_type_(stored_type),
- custom_data_access_(custom_data_access),
- as_read_attribute_(as_read_attribute),
- as_write_attribute_(as_write_attribute),
- update_on_write_(update_on_write)
- {
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
-
- ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- const void *data = CustomData_get_layer(custom_data, stored_type_);
- if (data == nullptr) {
- return {};
- }
- return as_read_attribute_(data, domain_size);
+ const int domain_size = component.attribute_domain_size(domain_);
+ void *data = CustomData_get_layer(custom_data, stored_type_);
+ if (data == nullptr) {
+ return {};
}
-
- WriteAttributePtr try_get_for_write(GeometryComponent &component) const final
- {
- if (writable_ != Writable) {
- return {};
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- void *data = CustomData_get_layer(custom_data, stored_type_);
- if (data == nullptr) {
- return {};
- }
- void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
- if (data != new_data) {
- custom_data_access_.update_custom_data_pointers(component);
- data = new_data;
- }
- if (update_on_write_ != nullptr) {
- update_on_write_(component);
- }
- return as_write_attribute_(data, domain_size);
+ void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
+ if (data != new_data) {
+ custom_data_access_.update_custom_data_pointers(component);
+ data = new_data;
}
-
- bool try_delete(GeometryComponent &component) const final
- {
- if (deletable_ != Deletable) {
- return false;
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
-
- const int domain_size = component.attribute_domain_size(domain_);
- const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
- const bool delete_success = CustomData_free_layer(
- custom_data, stored_type_, domain_size, layer_index);
- if (delete_success) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return delete_success;
+ if (update_on_write_ != nullptr) {
+ update_on_write_(component);
}
+ return as_write_attribute_(data, domain_size);
+}
- bool try_create(GeometryComponent &component) const final
- {
- if (createable_ != Creatable) {
- return false;
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
- /* Exists already. */
- return false;
- }
- const int domain_size = component.attribute_domain_size(domain_);
- const void *data = CustomData_add_layer(
- custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
- const bool success = data != nullptr;
- if (success) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return success;
- }
-
- bool exists(const GeometryComponent &component) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- const void *data = CustomData_get_layer(custom_data, stored_type_);
- return data != nullptr;
- }
-};
-
-/**
- * This is the attribute provider for most user generated attributes.
- */
-class CustomDataAttributeProvider final : public DynamicAttributesProvider {
- private:
- static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
- CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
- CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL;
- const AttributeDomain domain_;
- const CustomDataAccessInfo custom_data_access_;
-
- public:
- CustomDataAttributeProvider(const AttributeDomain domain,
- const CustomDataAccessInfo custom_data_access)
- : domain_(domain), custom_data_access_(custom_data_access)
- {
+bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
+{
+ if (deletable_ != Deletable) {
+ return false;
}
-
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.name != attribute_name) {
- continue;
- }
- const CustomDataType data_type = (CustomDataType)layer.type;
- switch (data_type) {
- case CD_PROP_FLOAT:
- return this->layer_to_read_attribute<float>(layer, domain_size);
- case CD_PROP_FLOAT2:
- return this->layer_to_read_attribute<float2>(layer, domain_size);
- case CD_PROP_FLOAT3:
- return this->layer_to_read_attribute<float3>(layer, domain_size);
- case CD_PROP_INT32:
- return this->layer_to_read_attribute<int>(layer, domain_size);
- case CD_PROP_COLOR:
- return this->layer_to_read_attribute<Color4f>(layer, domain_size);
- case CD_PROP_BOOL:
- return this->layer_to_read_attribute<bool>(layer, domain_size);
- default:
- break;
- }
- }
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
return {};
}
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
- if (layer.name != attribute_name) {
- continue;
- }
- CustomData_duplicate_referenced_layer_named(
- custom_data, layer.type, layer.name, domain_size);
- const CustomDataType data_type = (CustomDataType)layer.type;
- switch (data_type) {
- case CD_PROP_FLOAT:
- return this->layer_to_write_attribute<float>(layer, domain_size);
- case CD_PROP_FLOAT2:
- return this->layer_to_write_attribute<float2>(layer, domain_size);
- case CD_PROP_FLOAT3:
- return this->layer_to_write_attribute<float3>(layer, domain_size);
- case CD_PROP_INT32:
- return this->layer_to_write_attribute<int>(layer, domain_size);
- case CD_PROP_COLOR:
- return this->layer_to_write_attribute<Color4f>(layer, domain_size);
- case CD_PROP_BOOL:
- return this->layer_to_write_attribute<bool>(layer, domain_size);
- default:
- break;
- }
- }
- return {};
+ const int domain_size = component.attribute_domain_size(domain_);
+ const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
+ const bool delete_success = CustomData_free_layer(
+ custom_data, stored_type_, domain_size, layer_index);
+ if (delete_success) {
+ custom_data_access_.update_custom_data_pointers(component);
}
+ return delete_success;
+}
- bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- const int domain_size = component.attribute_domain_size(domain_);
- for (const int i : IndexRange(custom_data->totlayer)) {
- const CustomDataLayer &layer = custom_data->layers[i];
- if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) {
- CustomData_free_layer(custom_data, layer.type, domain_size, i);
- return true;
- }
- }
+bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const
+{
+ if (createable_ != Creatable) {
return false;
}
-
- bool try_create(GeometryComponent &component,
- const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type) const final
- {
- if (domain_ != domain) {
- return false;
- }
- if (!this->type_is_supported(data_type)) {
- return false;
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.name == attribute_name) {
- return false;
- }
- }
- const int domain_size = component.attribute_domain_size(domain_);
- char attribute_name_c[MAX_NAME];
- attribute_name.copy(attribute_name_c);
- CustomData_add_layer_named(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
- return true;
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
}
-
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return true;
- }
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- const CustomDataType data_type = (CustomDataType)layer.type;
- if (this->type_is_supported(data_type)) {
- AttributeMetaData meta_data{domain_, data_type};
- if (!callback(layer.name, meta_data)) {
- return false;
- }
- }
- }
- return true;
+ if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
+ /* Exists already. */
+ return false;
}
-
- void supported_domains(Vector<AttributeDomain> &r_domains) const final
- {
- r_domains.append_non_duplicates(domain_);
+ const int domain_size = component.attribute_domain_size(domain_);
+ const void *data = CustomData_add_layer(
+ custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
+ const bool success = data != nullptr;
+ if (success) {
+ custom_data_access_.update_custom_data_pointers(component);
}
+ return success;
+}
- private:
- template<typename T>
- ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
- const int domain_size) const
- {
- return std::make_unique<ArrayReadAttribute<T>>(
- domain_, Span(static_cast<const T *>(layer.data), domain_size));
+bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
}
+ const void *data = CustomData_get_layer(custom_data, stored_type_);
+ return data != nullptr;
+}
- template<typename T>
- WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
- {
- return std::make_unique<ArrayWriteAttribute<T>>(
- domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
+ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
+ const GeometryComponent &component, const StringRef attribute_name) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
-
- bool type_is_supported(CustomDataType data_type) const
- {
- return ((1ULL << data_type) & supported_types_mask) != 0;
+ const int domain_size = component.attribute_domain_size(domain_);
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.name != attribute_name) {
+ continue;
+ }
+ const CustomDataType data_type = (CustomDataType)layer.type;
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return this->layer_to_read_attribute<float>(layer, domain_size);
+ case CD_PROP_FLOAT2:
+ return this->layer_to_read_attribute<float2>(layer, domain_size);
+ case CD_PROP_FLOAT3:
+ return this->layer_to_read_attribute<float3>(layer, domain_size);
+ case CD_PROP_INT32:
+ return this->layer_to_read_attribute<int>(layer, domain_size);
+ case CD_PROP_COLOR:
+ return this->layer_to_read_attribute<Color4f>(layer, domain_size);
+ case CD_PROP_BOOL:
+ return this->layer_to_read_attribute<bool>(layer, domain_size);
+ default:
+ break;
+ }
}
-};
-
-static Mesh *get_mesh_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- return mesh_component.get_for_write();
+ return {};
}
-static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
+WriteAttributePtr CustomDataAttributeProvider::try_get_for_write(
+ GeometryComponent &component, const StringRef attribute_name) const
{
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return mesh_component.get_for_read();
-}
-
-/**
- * This attribute provider is used for uv maps and vertex colors.
- */
-class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
- private:
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
- const AttributeDomain domain_;
- const CustomDataType attribute_type_;
- const CustomDataType stored_type_;
- const CustomDataAccessInfo custom_data_access_;
- const AsReadAttribute as_read_attribute_;
- const AsWriteAttribute as_write_attribute_;
-
- public:
- NamedLegacyCustomDataProvider(const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
- const CustomDataAccessInfo custom_data_access,
- const AsReadAttribute as_read_attribute,
- const AsWriteAttribute as_write_attribute)
- : domain_(domain),
- attribute_type_(attribute_type),
- stored_type_(stored_type),
- custom_data_access_(custom_data_access),
- as_read_attribute_(as_read_attribute),
- as_write_attribute_(as_write_attribute)
- {
- }
-
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.type == stored_type_) {
- if (layer.name == attribute_name) {
- const int domain_size = component.attribute_domain_size(domain_);
- return as_read_attribute_(layer.data, domain_size);
- }
- }
- }
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
return {};
}
-
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
- if (layer.type == stored_type_) {
- if (layer.name == attribute_name) {
- const int domain_size = component.attribute_domain_size(domain_);
- void *data_old = layer.data;
- void *data_new = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, layer.name, domain_size);
- if (data_old != data_new) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return as_write_attribute_(layer.data, domain_size);
- }
- }
+ const int domain_size = component.attribute_domain_size(domain_);
+ for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
+ if (layer.name != attribute_name) {
+ continue;
+ }
+ CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size);
+ const CustomDataType data_type = (CustomDataType)layer.type;
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return this->layer_to_write_attribute<float>(layer, domain_size);
+ case CD_PROP_FLOAT2:
+ return this->layer_to_write_attribute<float2>(layer, domain_size);
+ case CD_PROP_FLOAT3:
+ return this->layer_to_write_attribute<float3>(layer, domain_size);
+ case CD_PROP_INT32:
+ return this->layer_to_write_attribute<int>(layer, domain_size);
+ case CD_PROP_COLOR:
+ return this->layer_to_write_attribute<Color4f>(layer, domain_size);
+ case CD_PROP_BOOL:
+ return this->layer_to_write_attribute<bool>(layer, domain_size);
+ default:
+ break;
}
- return {};
}
+ return {};
+}
- bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- for (const int i : IndexRange(custom_data->totlayer)) {
- const CustomDataLayer &layer = custom_data->layers[i];
- if (layer.type == stored_type_) {
- if (layer.name == attribute_name) {
- const int domain_size = component.attribute_domain_size(domain_);
- CustomData_free_layer(custom_data, stored_type_, domain_size, i);
- custom_data_access_.update_custom_data_pointers(component);
- return true;
- }
- }
- }
+bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
+ const StringRef attribute_name) const
+{
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
return false;
}
-
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ for (const int i : IndexRange(custom_data->totlayer)) {
+ const CustomDataLayer &layer = custom_data->layers[i];
+ if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) {
+ CustomData_free_layer(custom_data, layer.type, domain_size, i);
return true;
}
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.type == stored_type_) {
- AttributeMetaData meta_data{domain_, attribute_type_};
- if (!callback(layer.name, meta_data)) {
- return false;
- }
- }
- }
- return true;
}
+ return false;
+}
- void supported_domains(Vector<AttributeDomain> &r_domains) const final
- {
- r_domains.append_non_duplicates(domain_);
+bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type) const
+{
+ if (domain_ != domain) {
+ return false;
}
-};
-
-/**
- * This provider makes vertex groups available as float attributes.
- */
-class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
- public:
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
- attribute_name, -1);
- if (vertex_group_index < 0) {
- return {};
- }
- if (mesh == nullptr || mesh->dvert == nullptr) {
- static const float default_value = 0.0f;
- return std::make_unique<ConstantReadAttribute>(
- ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
- }
- return std::make_unique<VertexWeightReadAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ if (!this->type_is_supported(data_type)) {
+ return false;
}
-
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh == nullptr) {
- return {};
- }
- const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
- attribute_name, -1);
- if (vertex_group_index < 0) {
- return {};
- }
- if (mesh->dvert == nullptr) {
- BKE_object_defgroup_data_create(&mesh->id);
- }
- else {
- /* Copy the data layer if it is shared with some other mesh. */
- mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
- &mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
- }
- return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
}
-
- bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
-
- const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as(
- attribute_name, -1);
- if (vertex_group_index < 0) {
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.name == attribute_name) {
return false;
}
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh == nullptr) {
- return true;
- }
- if (mesh->dvert == nullptr) {
- return true;
- }
- for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
- MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
- BKE_defvert_remove_group(&dvert, weight);
- }
- return true;
}
+ const int domain_size = component.attribute_domain_size(domain_);
+ char attribute_name_c[MAX_NAME];
+ attribute_name.copy(attribute_name_c);
+ CustomData_add_layer_named(
+ custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ return true;
+}
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- for (const auto item : mesh_component.vertex_group_names().items()) {
- const StringRefNull name = item.key;
- const int vertex_group_index = item.value;
- if (vertex_group_index >= 0) {
- AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT};
- if (!callback(name, meta_data)) {
- return false;
- }
- }
- }
+bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
return true;
}
-
- void supported_domains(Vector<AttributeDomain> &r_domains) const final
- {
- r_domains.append_non_duplicates(ATTR_DOMAIN_POINT);
- }
-};
-
-/**
- * This is a container for multiple attribute providers that are used by one geometry component
- * type (e.g. there is a set of attribute providers for mesh components).
- */
-class ComponentAttributeProviders {
- private:
- /**
- * Builtin attribute providers are identified by their name. Attribute names that are in this
- * map will only be accessed using builtin attribute providers. Therefore, these providers have
- * higher priority when an attribute name is looked up. Usually, that means that builtin
- * providers are checked before dynamic ones.
- */
- Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
- /**
- * An ordered list of dynamic attribute providers. The order is important because that is order
- * in which they are checked when an attribute is looked up.
- */
- Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
- /**
- * All the domains that are supported by at least one of the providers above.
- */
- Vector<AttributeDomain> supported_domains_;
-
- public:
- ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
- Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
- : dynamic_attribute_providers_(dynamic_attribute_providers)
- {
- Set<AttributeDomain> domains;
- for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) {
- /* Use #add_new to make sure that no two builtin attributes have the same name. */
- builtin_attribute_providers_.add_new(provider->name(), provider);
- supported_domains_.append_non_duplicates(provider->domain());
- }
- for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
- provider->supported_domains(supported_domains_);
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ const CustomDataType data_type = (CustomDataType)layer.type;
+ if (this->type_is_supported(data_type)) {
+ AttributeMetaData meta_data{domain_, data_type};
+ if (!callback(layer.name, meta_data)) {
+ return false;
+ }
}
}
-
- const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const
- {
- return builtin_attribute_providers_;
- }
-
- Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
- {
- return dynamic_attribute_providers_;
- }
-
- Span<AttributeDomain> supported_domains() const
- {
- return supported_domains_;
- }
-};
-
-static float3 get_vertex_position(const MVert &vert)
-{
- return float3(vert.co);
-}
-
-static void set_vertex_position(MVert &vert, const float3 &position)
-{
- copy_v3_v3(vert.co, position);
-}
-
-static ReadAttributePtr make_vertex_position_read_attribute(const void *data,
- const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>(
- ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size));
+ return true;
}
-static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size)
+ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
+ const GeometryComponent &component, const StringRef attribute_name) const
{
- return std::make_unique<
- DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>(
- ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size));
-}
-
-static void tag_normals_dirty_when_writing_position(GeometryComponent &component)
-{
- Mesh *mesh = get_mesh_from_component_for_write(component);
- if (mesh != nullptr) {
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.type == stored_type_) {
+ if (layer.name == attribute_name) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ return as_read_attribute_(layer.data, domain_size);
+ }
+ }
+ }
+ return {};
}
-static int get_material_index(const MPoly &mpoly)
-{
- return static_cast<int>(mpoly.mat_nr);
-}
-
-static void set_material_index(MPoly &mpoly, const int &index)
-{
- mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
-}
-
-static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>(
- ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
-}
-
-static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size)
-{
- return std::make_unique<
- DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>(
- ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
-}
-
-static float2 get_loop_uv(const MLoopUV &uv)
-{
- return float2(uv.uv);
-}
-
-static void set_loop_uv(MLoopUV &uv, const float2 &co)
-{
- copy_v2_v2(uv.uv, co);
-}
-
-static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>(
- ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size));
-}
-
-static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>(
- ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size));
-}
-
-static Color4f get_loop_color(const MLoopCol &col)
-{
- Color4f value;
- rgba_uchar_to_float(value, &col.r);
- return value;
-}
-
-static void set_loop_color(MLoopCol &col, const Color4f &value)
-{
- rgba_float_to_uchar(&col.r, value);
-}
-
-static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>(
- ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size));
-}
-
-static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size)
-{
- return std::make_unique<
- DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>(
- ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size));
-}
-
-template<typename T, AttributeDomain Domain>
-static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
+WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
+ GeometryComponent &component, const StringRef attribute_name) const
{
- return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
+ }
+ for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
+ if (layer.type == stored_type_) {
+ if (layer.name == attribute_name) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ void *data_old = layer.data;
+ void *data_new = CustomData_duplicate_referenced_layer_named(
+ custom_data, stored_type_, layer.name, domain_size);
+ if (data_old != data_new) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
+ return as_write_attribute_(layer.data, domain_size);
+ }
+ }
+ }
+ return {};
}
-template<typename T, AttributeDomain Domain>
-static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
+ const StringRef attribute_name) const
{
- return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
+ }
+ for (const int i : IndexRange(custom_data->totlayer)) {
+ const CustomDataLayer &layer = custom_data->layers[i];
+ if (layer.type == stored_type_) {
+ if (layer.name == attribute_name) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ CustomData_free_layer(custom_data, stored_type_, domain_size, i);
+ custom_data_access_.update_custom_data_pointers(component);
+ return true;
+ }
+ }
+ }
+ return false;
}
-/**
- * In this function all the attribute providers for a mesh component are created. Most data in this
- * function is statically allocated, because it does not change over time.
- */
-static ComponentAttributeProviders create_attribute_providers_for_mesh()
+bool NamedLegacyCustomDataProvider::foreach_attribute(
+ const GeometryComponent &component, const AttributeForeachCallback callback) const
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- Mesh *mesh = get_mesh_from_component_for_write(component);
- if (mesh != nullptr) {
- BKE_mesh_update_customdata_pointers(mesh, false);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return true;
+ }
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.type == stored_type_) {
+ AttributeMetaData meta_data{domain_, attribute_type_};
+ if (!callback(layer.name, meta_data)) {
+ return false;
+ }
}
- };
-
-#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
- [](GeometryComponent &component) -> CustomData * { \
- Mesh *mesh = get_mesh_from_component_for_write(component); \
- return mesh ? &mesh->NAME : nullptr; \
- }
-#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
- [](const GeometryComponent &component) -> const CustomData * { \
- const Mesh *mesh = get_mesh_from_component_for_read(component); \
- return mesh ? &mesh->NAME : nullptr; \
- }
-
- static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
- MAKE_CONST_CUSTOM_DATA_GETTER(ldata),
- update_custom_data_pointers};
- static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
- MAKE_CONST_CUSTOM_DATA_GETTER(vdata),
- update_custom_data_pointers};
- static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
- MAKE_CONST_CUSTOM_DATA_GETTER(edata),
- update_custom_data_pointers};
- static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
- MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
- update_custom_data_pointers};
-
-#undef MAKE_CONST_CUSTOM_DATA_GETTER
-#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
-
- static BuiltinCustomDataLayerProvider position("position",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- CD_MVERT,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- point_access,
- make_vertex_position_read_attribute,
- make_vertex_position_write_attribute,
- tag_normals_dirty_when_writing_position);
-
- static BuiltinCustomDataLayerProvider material_index("material_index",
- ATTR_DOMAIN_POLYGON,
- CD_PROP_INT32,
- CD_MPOLY,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- polygon_access,
- make_material_index_read_attribute,
- make_material_index_write_attribute,
- nullptr);
-
- static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER,
- CD_PROP_FLOAT2,
- CD_MLOOPUV,
- corner_access,
- make_uvs_read_attribute,
- make_uvs_write_attribute);
-
- static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER,
- CD_PROP_COLOR,
- CD_MLOOPCOL,
- corner_access,
- make_vertex_color_read_attribute,
- make_vertex_color_write_attribute);
-
- static VertexGroupsAttributeProvider vertex_groups;
- static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
- static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
- static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
- static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access);
-
- return ComponentAttributeProviders({&position, &material_index},
- {&uvs,
- &vertex_colors,
- &corner_custom_data,
- &vertex_groups,
- &point_custom_data,
- &edge_custom_data,
- &polygon_custom_data});
+ }
+ return true;
}
-/**
- * In this function all the attribute providers for a point cloud component are created. Most data
- * in this function is statically allocated, because it does not change over time.
- */
-static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
+void NamedLegacyCustomDataProvider::foreach_domain(
+ const FunctionRef<void(AttributeDomain)> callback) const
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- PointCloud *pointcloud = pointcloud_component.get_for_write();
- if (pointcloud != nullptr) {
- BKE_pointcloud_update_customdata_pointers(pointcloud);
- }
- };
- static CustomDataAccessInfo point_access = {
- [](GeometryComponent &component) -> CustomData * {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- PointCloud *pointcloud = pointcloud_component.get_for_write();
- return pointcloud ? &pointcloud->pdata : nullptr;
- },
- [](const GeometryComponent &component) -> const CustomData * {
- const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
- component);
- const PointCloud *pointcloud = pointcloud_component.get_for_read();
- return pointcloud ? &pointcloud->pdata : nullptr;
- },
- update_custom_data_pointers};
-
- static BuiltinCustomDataLayerProvider position(
- "position",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- CD_PROP_FLOAT3,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- point_access,
- make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
- nullptr);
- static BuiltinCustomDataLayerProvider radius(
- "radius",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT,
- BuiltinAttributeProvider::Creatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::Deletable,
- point_access,
- make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
- nullptr);
- static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
- return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
+ callback(domain_);
}
} // namespace blender::bke
@@ -1999,173 +1121,3 @@ void OutputAttributePtr::apply_span_and_save()
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Point Cloud Component
- * \{ */
-
-const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
- const
-{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_point_cloud();
- return &providers;
-}
-
-int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
-{
- BLI_assert(domain == ATTR_DOMAIN_POINT);
- UNUSED_VARS_NDEBUG(domain);
- if (pointcloud_ == nullptr) {
- return 0;
- }
- return pointcloud_->totpoint;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Mesh Component
- * \{ */
-
-const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
-{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_mesh();
- return &providers;
-}
-
-int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
-{
- BLI_assert(this->attribute_domain_supported(domain));
- if (mesh_ == nullptr) {
- return 0;
- }
- switch (domain) {
- case ATTR_DOMAIN_CORNER:
- return mesh_->totloop;
- case ATTR_DOMAIN_POINT:
- return mesh_->totvert;
- case ATTR_DOMAIN_EDGE:
- return mesh_->totedge;
- case ATTR_DOMAIN_POLYGON:
- return mesh_->totpoly;
- default:
- BLI_assert(false);
- break;
- }
- return 0;
-}
-
-namespace blender::bke {
-
-template<typename T>
-static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totvert);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int loop_index : IndexRange(mesh.totloop)) {
- const T value = attribute[loop_index];
- const MLoop &loop = mesh.mloop[loop_index];
- const int point_index = loop.v;
- mixer.mix_in(point_index, value);
- }
- mixer.finalize();
-}
-
-static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
-{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- /* We compute all interpolated values at once, because for this interpolation, one has to
- * iterate over all loops anyway. */
- Array<T> values(mesh.totvert);
- adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
- }
- });
- return new_attribute;
-}
-
-template<typename T>
-static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totloop);
-
- for (const int loop_index : IndexRange(mesh.totloop)) {
- const int vertex_index = mesh.mloop[loop_index].v;
- r_values[loop_index] = attribute[vertex_index];
- }
-}
-
-static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
-{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- /* It is not strictly necessary to compute the value for all corners here. Instead one could
- * lazily lookup the mesh topology when a specific index accessed. This can be more efficient
- * when an algorithm only accesses very few of the corner values. However, for the algorithms
- * we currently have, precomputing the array is fine. Also, it is easier to implement. */
- Array<T> values(mesh.totloop);
- adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
- std::move(values));
- });
- return new_attribute;
-}
-
-} // namespace blender::bke
-
-ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
- const AttributeDomain new_domain) const
-{
- if (!attribute) {
- return {};
- }
- if (attribute->size() == 0) {
- return {};
- }
- const AttributeDomain old_domain = attribute->domain();
- if (old_domain == new_domain) {
- return attribute;
- }
-
- switch (old_domain) {
- case ATTR_DOMAIN_CORNER: {
- switch (new_domain) {
- case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
- default:
- break;
- }
- break;
- }
- case ATTR_DOMAIN_POINT: {
- switch (new_domain) {
- case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
- default:
- break;
- }
- }
- default:
- break;
- }
-
- return {};
-}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
new file mode 100644
index 00000000000..806d10e9e89
--- /dev/null
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -0,0 +1,494 @@
+/*
+ * 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_map.hh"
+#include "BLI_span.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "BKE_geometry_set.hh"
+
+namespace blender::bke {
+
+class ConstantReadAttribute final : public ReadAttribute {
+ private:
+ void *value_;
+
+ public:
+ ConstantReadAttribute(AttributeDomain domain,
+ const int64_t size,
+ const CPPType &type,
+ const void *value)
+ : ReadAttribute(domain, type, size)
+ {
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_to_uninitialized(value, value_);
+ }
+
+ ~ConstantReadAttribute() override
+ {
+ this->cpp_type_.destruct(value_);
+ MEM_freeN(value_);
+ }
+
+ void get_internal(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->cpp_type_.copy_to_uninitialized(value_, r_value);
+ }
+
+ void initialize_span() const override
+ {
+ const int element_size = cpp_type_.size();
+ array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
+ array_is_temporary_ = true;
+ cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
+ }
+};
+
+template<typename T> class ArrayReadAttribute final : public ReadAttribute {
+ private:
+ Span<T> data_;
+
+ public:
+ ArrayReadAttribute(AttributeDomain domain, Span<T> data)
+ : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void initialize_span() const override
+ {
+ /* The data will not be modified, so this const_cast is fine. */
+ array_buffer_ = const_cast<T *>(data_.data());
+ array_is_temporary_ = false;
+ }
+};
+
+template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
+ private:
+ Array<T> data_;
+
+ public:
+ OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
+ : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void initialize_span() const override
+ {
+ /* The data will not be modified, so this const_cast is fine. */
+ array_buffer_ = const_cast<T *>(data_.data());
+ array_is_temporary_ = false;
+ }
+};
+
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class DerivedArrayReadAttribute final : public ReadAttribute {
+ private:
+ Span<StructT> data_;
+
+ public:
+ DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
+ : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ const StructT &struct_value = data_[index];
+ const ElemT value = GetFunc(struct_value);
+ new (r_value) ElemT(value);
+ }
+};
+
+template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
+ private:
+ MutableSpan<T> data_;
+
+ public:
+ ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
+ : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ data_[index] = *reinterpret_cast<const T *>(value);
+ }
+
+ void initialize_span(const bool UNUSED(write_only)) override
+ {
+ array_buffer_ = data_.data();
+ array_is_temporary_ = false;
+ }
+
+ void apply_span_if_necessary() override
+ {
+ /* Do nothing, because the span contains the attribute itself already. */
+ }
+};
+
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, const ElemT &)>
+class DerivedArrayWriteAttribute final : public WriteAttribute {
+ private:
+ MutableSpan<StructT> data_;
+
+ public:
+ DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
+ : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ const StructT &struct_value = data_[index];
+ const ElemT value = GetFunc(struct_value);
+ new (r_value) ElemT(value);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ StructT &struct_value = data_[index];
+ const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
+ SetFunc(struct_value, typed_value);
+ }
+};
+
+/**
+ * Utility to group together multiple functions that are used to access custom data on geometry
+ * components in a generic way.
+ */
+struct CustomDataAccessInfo {
+ using CustomDataGetter = CustomData *(*)(GeometryComponent &component);
+ using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component);
+ using UpdateCustomDataPointers = void (*)(GeometryComponent &component);
+
+ CustomDataGetter get_custom_data;
+ ConstCustomDataGetter get_const_custom_data;
+ UpdateCustomDataPointers update_custom_data_pointers;
+};
+
+/**
+ * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component.
+ * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do
+ * not follow the same loose rules as other attributes, because they are mapped to internal
+ * "legacy" data structures. For example, some builtin attributes cannot be deleted. */
+class BuiltinAttributeProvider {
+ public:
+ /* Some utility enums to avoid hard to read booleans in function calls. */
+ enum CreatableEnum {
+ Creatable,
+ NonCreatable,
+ };
+ enum WritableEnum {
+ Writable,
+ Readonly,
+ };
+ enum DeletableEnum {
+ Deletable,
+ NonDeletable,
+ };
+
+ protected:
+ const std::string name_;
+ const AttributeDomain domain_;
+ const CustomDataType data_type_;
+ const CreatableEnum createable_;
+ const WritableEnum writable_;
+ const DeletableEnum deletable_;
+
+ public:
+ BuiltinAttributeProvider(std::string name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const CreatableEnum createable,
+ const WritableEnum writable,
+ const DeletableEnum deletable)
+ : name_(std::move(name)),
+ domain_(domain),
+ data_type_(data_type),
+ createable_(createable),
+ writable_(writable),
+ deletable_(deletable)
+ {
+ }
+
+ virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
+ virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
+ virtual bool try_delete(GeometryComponent &component) const = 0;
+ virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
+ virtual bool exists(const GeometryComponent &component) const = 0;
+
+ StringRefNull name() const
+ {
+ return name_;
+ }
+
+ AttributeDomain domain() const
+ {
+ return domain_;
+ }
+
+ CustomDataType data_type() const
+ {
+ return data_type_;
+ }
+};
+
+/**
+ * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each
+ * attribute has a name, domain and type.
+ */
+class DynamicAttributesProvider {
+ public:
+ virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const = 0;
+ virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const = 0;
+ virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
+ virtual bool try_create(GeometryComponent &UNUSED(component),
+ const StringRef UNUSED(attribute_name),
+ const AttributeDomain UNUSED(domain),
+ const CustomDataType UNUSED(data_type)) const
+ {
+ /* Some providers should not create new attributes. */
+ return false;
+ };
+
+ virtual bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const = 0;
+ virtual void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const = 0;
+};
+
+/**
+ * This is the attribute provider for most user generated attributes.
+ */
+class CustomDataAttributeProvider final : public DynamicAttributesProvider {
+ private:
+ static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
+ CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
+ CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL;
+ const AttributeDomain domain_;
+ const CustomDataAccessInfo custom_data_access_;
+
+ public:
+ CustomDataAttributeProvider(const AttributeDomain domain,
+ const CustomDataAccessInfo custom_data_access)
+ : domain_(domain), custom_data_access_(custom_data_access)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
+
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
+
+ bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
+
+ bool try_create(GeometryComponent &component,
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type) const final;
+
+ bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const final;
+
+ void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ {
+ callback(domain_);
+ }
+
+ private:
+ template<typename T>
+ ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
+ const int domain_size) const
+ {
+ return std::make_unique<ArrayReadAttribute<T>>(
+ domain_, Span(static_cast<const T *>(layer.data), domain_size));
+ }
+
+ template<typename T>
+ WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
+ {
+ return std::make_unique<ArrayWriteAttribute<T>>(
+ domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
+ }
+
+ bool type_is_supported(CustomDataType data_type) const
+ {
+ return ((1ULL << data_type) & supported_types_mask) != 0;
+ }
+};
+
+/**
+ * This attribute provider is used for uv maps and vertex colors.
+ */
+class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
+ private:
+ using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ const AttributeDomain domain_;
+ const CustomDataType attribute_type_;
+ const CustomDataType stored_type_;
+ const CustomDataAccessInfo custom_data_access_;
+ const AsReadAttribute as_read_attribute_;
+ const AsWriteAttribute as_write_attribute_;
+
+ public:
+ NamedLegacyCustomDataProvider(const AttributeDomain domain,
+ const CustomDataType attribute_type,
+ const CustomDataType stored_type,
+ const CustomDataAccessInfo custom_data_access,
+ const AsReadAttribute as_read_attribute,
+ const AsWriteAttribute as_write_attribute)
+ : domain_(domain),
+ attribute_type_(attribute_type),
+ stored_type_(stored_type),
+ custom_data_access_(custom_data_access),
+ as_read_attribute_(as_read_attribute),
+ as_write_attribute_(as_write_attribute)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
+ bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
+ bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const final;
+ void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final;
+};
+
+/**
+ * This provider is used to provide access to builtin attributes. It supports making internal types
+ * available as different types. For example, the vertex position attribute is stored as part of
+ * the #MVert struct, but is exposed as float3 attribute.
+ */
+class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
+ using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ using UpdateOnRead = void (*)(const GeometryComponent &component);
+ using UpdateOnWrite = void (*)(GeometryComponent &component);
+ const CustomDataType stored_type_;
+ const CustomDataAccessInfo custom_data_access_;
+ const AsReadAttribute as_read_attribute_;
+ const AsWriteAttribute as_write_attribute_;
+ const UpdateOnWrite update_on_write_;
+
+ public:
+ BuiltinCustomDataLayerProvider(std::string attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType attribute_type,
+ const CustomDataType stored_type,
+ const CreatableEnum creatable,
+ const WritableEnum writable,
+ const DeletableEnum deletable,
+ const CustomDataAccessInfo custom_data_access,
+ const AsReadAttribute as_read_attribute,
+ const AsWriteAttribute as_write_attribute,
+ const UpdateOnWrite update_on_write)
+ : BuiltinAttributeProvider(
+ std::move(attribute_name), domain, attribute_type, creatable, writable, deletable),
+ stored_type_(stored_type),
+ custom_data_access_(custom_data_access),
+ as_read_attribute_(as_read_attribute),
+ as_write_attribute_(as_write_attribute),
+ update_on_write_(update_on_write)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final;
+ WriteAttributePtr try_get_for_write(GeometryComponent &component) const final;
+ bool try_delete(GeometryComponent &component) const final;
+ bool try_create(GeometryComponent &component) const final;
+ bool exists(const GeometryComponent &component) const final;
+};
+
+/**
+ * This is a container for multiple attribute providers that are used by one geometry component
+ * type (e.g. there is a set of attribute providers for mesh components).
+ */
+class ComponentAttributeProviders {
+ private:
+ /**
+ * Builtin attribute providers are identified by their name. Attribute names that are in this
+ * map will only be accessed using builtin attribute providers. Therefore, these providers have
+ * higher priority when an attribute name is looked up. Usually, that means that builtin
+ * providers are checked before dynamic ones.
+ */
+ Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
+ /**
+ * An ordered list of dynamic attribute providers. The order is important because that is order
+ * in which they are checked when an attribute is looked up.
+ */
+ Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
+ /**
+ * All the domains that are supported by at least one of the providers above.
+ */
+ VectorSet<AttributeDomain> supported_domains_;
+
+ public:
+ ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
+ Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
+ : dynamic_attribute_providers_(dynamic_attribute_providers)
+ {
+ for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) {
+ /* Use #add_new to make sure that no two builtin attributes have the same name. */
+ builtin_attribute_providers_.add_new(provider->name(), provider);
+ supported_domains_.add(provider->domain());
+ }
+ for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
+ provider->foreach_domain([&](AttributeDomain domain) { supported_domains_.add(domain); });
+ }
+ }
+
+ const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const
+ {
+ return builtin_attribute_providers_;
+ }
+
+ Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
+ {
+ return dynamic_attribute_providers_;
+ }
+
+ Span<AttributeDomain> supported_domains() const
+ {
+ return supported_domains_;
+ }
+};
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index 9f5e038fb82..ec8962d5f6d 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -94,8 +94,9 @@ bool BKE_copybuffer_read(Main *bmain_dst,
}
/* Here appending/linking starts. */
const int flag = 0;
+ const int id_tag_extra = 0;
struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init(&liblink_params, bmain_dst, flag);
+ BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra);
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, &liblink_params);
@@ -130,6 +131,7 @@ int BKE_copybuffer_paste(bContext *C,
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
+ const int id_tag_extra = 0;
bh = BLO_blendhandle_from_file(libname, reports);
@@ -148,7 +150,8 @@ int BKE_copybuffer_paste(bContext *C,
/* here appending/linking starts */
struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init_with_context(&liblink_params, bmain, flag, scene, view_layer, v3d);
+ BLO_library_link_params_init_with_context(
+ &liblink_params, bmain, flag, id_tag_extra, 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);
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index d826aaf24e3..293b2c9c4c6 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -77,7 +77,12 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK) {
- success = BKE_blendfile_read(C, mfu->filename, &(const struct BlendFileReadParams){0}, NULL);
+ const struct BlendFileReadParams params = {0};
+ struct BlendFileData *bfd = BKE_blendfile_read(mfu->filename, &params, NULL);
+ if (bfd != NULL) {
+ BKE_blendfile_read_setup(C, bfd, &params, NULL);
+ success = true;
+ }
}
else {
struct BlendFileReadParams params = {0};
@@ -85,7 +90,12 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
if (!use_old_bmain_data) {
params.skip_flags |= BLO_READ_SKIP_UNDO_OLD_MAIN;
}
- success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, &params, NULL);
+ struct BlendFileData *bfd = BKE_blendfile_read_from_memfile(
+ bmain, &mfu->memfile, &params, NULL);
+ if (bfd != NULL) {
+ BKE_blendfile_read_setup(C, bfd, &params, NULL);
+ success = true;
+ }
}
/* Restore, bmain has been re-allocated. */
@@ -105,6 +115,9 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
{
MemFileUndoData *mfu = MEM_callocN(sizeof(MemFileUndoData), __func__);
+ /* Include recovery infomation since undo-data is written out as #BLENDER_QUIT_FILE. */
+ const int fileflags = G.fileflags | G_FILE_RECOVER_WRITE;
+
/* disk save version */
if (UNDO_DISK) {
static int counter = 0;
@@ -119,7 +132,7 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), numstr);
/* success = */ /* UNUSED */ BLO_write_file(
- bmain, filename, G.fileflags, &(const struct BlendFileWriteParams){0}, NULL);
+ bmain, filename, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename));
}
@@ -128,7 +141,7 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
if (prevfile) {
BLO_memfile_clear_future(prevfile);
}
- /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags);
+ /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, fileflags);
mfu->undo_size = mfu->memfile.size;
}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 32710c4fa60..efbf19c7381 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -51,6 +51,7 @@
#include "BKE_keyconfig.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_override.h"
#include "BKE_main.h"
#include "BKE_preferences.h"
#include "BKE_report.h"
@@ -131,17 +132,15 @@ static void setup_app_userdef(BlendFileData *bfd)
* should be avoided or check (mode != LOAD_UNDO).
*
* \param bfd: Blend file data, freed by this function on exit.
- * \param filepath: File path or identifier.
*/
static void setup_app_data(bContext *C,
BlendFileData *bfd,
- const char *filepath,
const struct BlendFileReadParams *params,
ReportList *reports)
{
Main *bmain = G_MAIN;
Scene *curscene = NULL;
- const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
+ const bool recover = (G.fileflags & G_FILE_RECOVER_READ) != 0;
const bool is_startup = params->is_startup;
enum {
LOAD_UI = 1,
@@ -349,16 +348,10 @@ static void setup_app_data(bContext *C,
if (is_startup) {
bmain->name[0] = '\0';
}
- else if (recover && G.relbase_valid) {
- /* in case of autosave or quit.blend, use original filename instead
- * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */
- filepath = bfd->filename;
+ else if (recover) {
+ /* In case of autosave or quit.blend, use original filename instead. */
bmain->recovered = 1;
-
- /* these are the same at times, should never copy to the same location */
- if (bmain->name != filepath) {
- BLI_strncpy(bmain->name, filepath, FILE_MAX);
- }
+ BLI_strncpy(bmain->name, bfd->filename, FILE_MAX);
}
/* baseflags, groups, make depsgraph, etc */
@@ -401,11 +394,17 @@ static void setup_app_data(bContext *C,
* to recompute refcount for all local IDs too. */
BKE_main_id_refcount_recompute(bmain, false);
}
+
+ if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
+ BKE_lib_override_library_main_resync(
+ bmain,
+ curscene,
+ bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene));
+ }
}
static void setup_app_blend_file_data(bContext *C,
BlendFileData *bfd,
- const char *filepath,
const struct BlendFileReadParams *params,
ReportList *reports)
{
@@ -413,7 +412,7 @@ static void setup_app_blend_file_data(bContext *C,
setup_app_userdef(bfd);
}
if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) {
- setup_app_data(C, bfd, filepath, params, reports);
+ setup_app_data(C, bfd, params, reports);
}
}
@@ -430,15 +429,46 @@ static void handle_subversion_warning(Main *main, ReportList *reports)
}
}
-bool BKE_blendfile_read_ex(bContext *C,
- const char *filepath,
- const struct BlendFileReadParams *params,
- ReportList *reports,
- /* Extra args. */
- const bool startup_update_defaults,
- const char *startup_app_template)
+/**
+ * Shared setup function that makes the data from `bfd` into the current blend file,
+ * replacing the contents of #G.main.
+ * This uses the bfd #BKE_blendfile_read and similarly named functions.
+ *
+ * This is done in a separate step so the caller may perform actions after it is known the file
+ * loaded correctly but before the file replaces the existing blend file contents.
+ */
+void BKE_blendfile_read_setup_ex(bContext *C,
+ BlendFileData *bfd,
+ const struct BlendFileReadParams *params,
+ ReportList *reports,
+ /* Extra args. */
+ const bool startup_update_defaults,
+ const char *startup_app_template)
{
+ if (startup_update_defaults) {
+ if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) {
+ BLO_update_defaults_startup_blend(bfd->main, startup_app_template);
+ }
+ }
+ setup_app_blend_file_data(C, bfd, params, reports);
+ BLO_blendfiledata_free(bfd);
+}
+
+void BKE_blendfile_read_setup(bContext *C,
+ BlendFileData *bfd,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
+{
+ BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL);
+}
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
+struct BlendFileData *BKE_blendfile_read(const char *filepath,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
+{
/* Don't print startup file loading. */
if (params->is_startup == false) {
printf("Read blend: %s\n", filepath);
@@ -447,69 +477,40 @@ bool BKE_blendfile_read_ex(bContext *C,
BlendFileData *bfd = BLO_read_from_file(filepath, params->skip_flags, reports);
if (bfd) {
handle_subversion_warning(bfd->main, reports);
- if (startup_update_defaults) {
- if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) {
- BLO_update_defaults_startup_blend(bfd->main, startup_app_template);
- }
- }
- setup_app_blend_file_data(C, bfd, filepath, params, reports);
- BLO_blendfiledata_free(bfd);
}
else {
BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
}
- return (bfd != NULL);
-}
-
-bool BKE_blendfile_read(bContext *C,
- const char *filepath,
- const struct BlendFileReadParams *params,
- ReportList *reports)
-{
- return BKE_blendfile_read_ex(C, filepath, params, reports, false, NULL);
+ return bfd;
}
-bool BKE_blendfile_read_from_memory_ex(bContext *C,
- const void *filebuf,
- int filelength,
- const struct BlendFileReadParams *params,
- ReportList *reports,
- /* Extra args. */
- const bool startup_update_defaults,
- const char *startup_app_template)
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
+struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
+ int filelength,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
{
BlendFileData *bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports);
if (bfd) {
- if (startup_update_defaults) {
- if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) {
- BLO_update_defaults_startup_blend(bfd->main, startup_app_template);
- }
- }
- setup_app_blend_file_data(C, bfd, "<memory2>", params, reports);
- BLO_blendfiledata_free(bfd);
+ /* Pass. */
}
else {
BKE_reports_prepend(reports, "Loading failed: ");
}
- return (bfd != NULL);
-}
-
-bool BKE_blendfile_read_from_memory(bContext *C,
- const void *filebuf,
- int filelength,
- const struct BlendFileReadParams *params,
- ReportList *reports)
-{
- return BKE_blendfile_read_from_memory_ex(C, filebuf, filelength, params, reports, false, NULL);
+ return bfd;
}
-/* memfile is the undo buffer */
-bool BKE_blendfile_read_from_memfile(bContext *C,
- struct MemFile *memfile,
- const struct BlendFileReadParams *params,
- ReportList *reports)
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ * \note `memfile` is the undo buffer.
+ */
+struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
+ struct MemFile *memfile,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
{
- Main *bmain = CTX_data_main(C);
BlendFileData *bfd = BLO_read_from_memfile(
bmain, BKE_main_blendfile_path(bmain), memfile, params, reports);
if (bfd) {
@@ -520,14 +521,11 @@ bool BKE_blendfile_read_from_memfile(bContext *C,
BLI_assert(BLI_listbase_is_empty(&bfd->main->wm));
BLI_assert(BLI_listbase_is_empty(&bfd->main->workspaces));
BLI_assert(BLI_listbase_is_empty(&bfd->main->screens));
-
- setup_app_blend_file_data(C, bfd, "<memory1>", params, reports);
- BLO_blendfiledata_free(bfd);
}
else {
BKE_reports_prepend(reports, "Loading failed: ");
}
- return (bfd != NULL);
+ return bfd;
}
/**
@@ -865,7 +863,7 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
ReportList *reports)
{
Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
- ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
+ ListBase *lbarray_dst[INDEX_ID_MAX], *lbarray_src[INDEX_ID_MAX];
int a, retval;
void *path_list_backup = NULL;
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 2ad0ac950d0..47427beccba 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -783,7 +783,7 @@ void BKE_bpath_traverse_main(Main *bmain,
const int flag,
void *bpath_user_data)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(bmain, lbarray);
while (a--) {
BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 28b91dcc8ce..4e4134c7c8f 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -122,7 +122,9 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
}
collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE_INSTANCED;
BLI_listbase_clear(&collection_dst->object_cache);
+ BLI_listbase_clear(&collection_dst->object_cache_instanced);
BLI_listbase_clear(&collection_dst->gobject);
BLI_listbase_clear(&collection_dst->children);
@@ -214,8 +216,10 @@ static void collection_blend_write(BlendWriter *writer, ID *id, const void *id_a
if (collection->id.us > 0 || BLO_write_is_undo(writer)) {
/* Clean up, important in undo case to reduce false detection of changed data-blocks. */
collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE_INSTANCED;
collection->tag = 0;
BLI_listbase_clear(&collection->object_cache);
+ BLI_listbase_clear(&collection->object_cache_instanced);
BLI_listbase_clear(&collection->parents);
/* write LibData */
@@ -246,8 +250,10 @@ void BKE_collection_blend_read_data(BlendDataReader *reader, Collection *collect
BKE_previewimg_blend_read(reader, collection->preview);
collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE_INSTANCED;
collection->tag = 0;
BLI_listbase_clear(&collection->object_cache);
+ BLI_listbase_clear(&collection->object_cache_instanced);
BLI_listbase_clear(&collection->parents);
#ifdef USE_COLLECTION_COMPAT_28
@@ -773,7 +779,10 @@ const char *BKE_collection_ui_name_get(struct Collection *collection)
/** \name Object List Cache
* \{ */
-static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict)
+static void collection_object_cache_fill(ListBase *lb,
+ Collection *collection,
+ int parent_restrict,
+ bool with_instances)
{
int child_restrict = collection->flag | parent_restrict;
@@ -784,6 +793,10 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i
base = MEM_callocN(sizeof(Base), "Object Base");
base->object = cob->ob;
BLI_addtail(lb, base);
+ if (with_instances && cob->ob->instance_collection) {
+ collection_object_cache_fill(
+ lb, cob->ob->instance_collection, child_restrict, with_instances);
+ }
}
/* Only collection flags are checked here currently, object restrict flag is checked
@@ -798,7 +811,7 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- collection_object_cache_fill(lb, child->collection, child_restrict);
+ collection_object_cache_fill(lb, child->collection, child_restrict, with_instances);
}
}
@@ -809,7 +822,7 @@ ListBase BKE_collection_object_cache_get(Collection *collection)
BLI_mutex_lock(&cache_lock);
if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
- collection_object_cache_fill(&collection->object_cache, collection, 0);
+ collection_object_cache_fill(&collection->object_cache, collection, 0, false);
collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
}
BLI_mutex_unlock(&cache_lock);
@@ -818,11 +831,29 @@ ListBase BKE_collection_object_cache_get(Collection *collection)
return collection->object_cache;
}
+ListBase BKE_collection_object_cache_instanced_get(Collection *collection)
+{
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE_INSTANCED)) {
+ static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
+
+ BLI_mutex_lock(&cache_lock);
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE_INSTANCED)) {
+ collection_object_cache_fill(&collection->object_cache_instanced, collection, 0, true);
+ collection->flag |= COLLECTION_HAS_OBJECT_CACHE_INSTANCED;
+ }
+ BLI_mutex_unlock(&cache_lock);
+ }
+
+ return collection->object_cache_instanced;
+}
+
static void collection_object_cache_free(Collection *collection)
{
/* Clear own cache an for all parents, since those are affected by changes as well. */
collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE_INSTANCED;
BLI_freelistN(&collection->object_cache);
+ BLI_freelistN(&collection->object_cache_instanced);
LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
collection_object_cache_free(parent->collection);
@@ -928,6 +959,16 @@ bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
return (BLI_findptr(&objects, ob, offsetof(Base, object)));
}
+bool BKE_collection_has_object_recursive_instanced(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ const ListBase objects = BKE_collection_object_cache_instanced_get(collection);
+ return (BLI_findptr(&objects, ob, offsetof(Base, object)));
+}
+
static Collection *collection_next_find(Main *bmain, Scene *scene, Collection *collection)
{
if (scene && collection == scene->master_collection) {
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 6bc385ecd31..cbf7a4483c0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -914,6 +914,15 @@ struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
return NULL;
}
+struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_SPREADSHEET) {
+ return area->spacedata.first;
+ }
+ return NULL;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 8a6b89ce19e..bc89fa85cea 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -30,6 +30,7 @@
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_dynstr.h"
@@ -50,10 +51,13 @@
struct CryptomatteSession {
blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer> layers;
+ /* Layer names in order of creation. */
+ blender::Vector<std::string> layer_names;
CryptomatteSession();
CryptomatteSession(const Main *bmain);
- CryptomatteSession(StampData *metadata);
+ CryptomatteSession(StampData *stamp_data);
+ CryptomatteSession(const Scene *scene);
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
std::optional<std::string> operator[](float encoded_hash) const;
@@ -99,8 +103,32 @@ CryptomatteSession::CryptomatteSession(StampData *stamp_data)
false);
}
+CryptomatteSession::CryptomatteSession(const Scene *scene)
+{
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
+ view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
+ if (cryptoflags == 0) {
+ cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
+ }
+
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoObject");
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoAsset");
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoMaterial");
+ }
+ }
+}
+
blender::bke::cryptomatte::CryptomatteLayer &CryptomatteSession::add_layer(std::string layer_name)
{
+ if (!layer_names.contains(layer_name)) {
+ layer_names.append(layer_name);
+ }
return layers.lookup_or_add_default(layer_name);
}
@@ -128,6 +156,12 @@ struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
return session;
}
+struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene)
+{
+ CryptomatteSession *session = new CryptomatteSession(scene);
+ return session;
+}
+
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name)
{
session->add_layer(layer_name);
@@ -182,39 +216,57 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
}
-char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
+/* Find an ID in the given main that matches the given encoded float. */
+bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
+ const float encoded_hash,
+ char *r_name,
+ int name_len)
{
- std::stringstream ss;
- ss.precision(9);
+ std::optional<std::string> name = (*session)[encoded_hash];
+ if (!name) {
+ return false;
+ }
+
+ BLI_strncpy(r_name, name->c_str(), name_len);
+ return true;
+}
+char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
+{
+ DynStr *matte_id = BLI_dynstr_new();
bool first = true;
LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
if (!first) {
- ss << ',';
+ BLI_dynstr_append(matte_id, ",");
}
- blender::StringRef entry_name(entry->name, BLI_strnlen(entry->name, sizeof(entry->name)));
- if (!entry_name.is_empty()) {
- ss << entry_name;
+ if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) {
+ BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
}
else {
- ss << '<' << std::scientific << entry->encoded_hash << '>';
+ BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
}
first = false;
}
-
- /* Convert result to C string. */
- const std::string result_string = ss.str();
- const char *c_str = result_string.c_str();
- size_t result_len = result_string.size() + 1;
- char *result = static_cast<char *>(MEM_mallocN(sizeof(char) * result_len, __func__));
- memcpy(result, c_str, result_len);
+ char *result = BLI_dynstr_get_cstring(matte_id);
+ BLI_dynstr_free(matte_id);
return result;
}
void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id)
{
BLI_freelistN(&node_storage->entries);
- std::optional<CryptomatteSession> session = std::nullopt;
+
+ if (matte_id == nullptr) {
+ MEM_SAFE_FREE(node_storage->matte_id);
+ return;
+ }
+ /* Update the matte_id so the files can be opened in versions that don't
+ * use `CryptomatteEntry`. */
+ if (matte_id != node_storage->matte_id && node_storage->matte_id &&
+ STREQ(node_storage->matte_id, matte_id)) {
+ MEM_SAFE_FREE(node_storage->matte_id);
+ node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id));
+ }
std::istringstream ss(matte_id);
while (ss.good()) {
@@ -358,6 +410,9 @@ static bool from_manifest(CryptomatteLayer &layer, blender::StringRefNull manife
ref = ref.drop_prefix(quoted_name_len);
ref = skip_whitespaces_(ref);
+ if (ref.is_empty()) {
+ return false;
+ }
char colon = ref.front();
if (colon != ':') {
return false;
@@ -365,7 +420,7 @@ static bool from_manifest(CryptomatteLayer &layer, blender::StringRefNull manife
ref = ref.drop_prefix(1);
ref = skip_whitespaces_(ref);
- if (ref.front() != '\"') {
+ if (ref.is_empty() || ref.front() != '\"') {
return false;
}
@@ -500,7 +555,7 @@ std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest(
blender::StringRefNull manifest)
{
std::unique_ptr<CryptomatteLayer> layer = std::make_unique<CryptomatteLayer>();
- blender::bke::cryptomatte::manifest::from_manifest(*layer.get(), manifest);
+ blender::bke::cryptomatte::manifest::from_manifest(*layer, manifest);
return layer;
}
@@ -597,4 +652,10 @@ void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
blender::bke::cryptomatte::manifest::from_manifest(layer, propvalue);
}
+const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
+ const CryptomatteSession &session)
+{
+ return session.layer_names;
+}
+
} // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc
index 5481b97913c..85ab7e43d22 100644
--- a/source/blender/blenkernel/intern/cryptomatte_test.cc
+++ b/source/blender/blenkernel/intern/cryptomatte_test.cc
@@ -21,8 +21,6 @@
#include "BKE_cryptomatte.hh"
#include "BKE_image.h"
-#include "DNA_node_types.h"
-
#include "RE_pipeline.h"
#include "MEM_guardedalloc.h"
@@ -77,17 +75,15 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest
TEST(cryptomatte, layer_from_manifest)
{
test_cryptomatte_manifest("{}", "{}");
- test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}");
- test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
- "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}");
- test_cryptomatte_manifest(
- "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
- " { \"Object\" : \"12345678\" , \"Object2\" : \"87654321\" } ");
- test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}",
- "{\"Object\\\"01\\\"\": \"12345678\"}");
+ test_cryptomatte_manifest(R"({"Object":"12345678"})", R"({"Object": "12345678"})");
+ test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})",
+ R"({"Object":"12345678","Object2":"87654321"})");
+ test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})",
+ R"( { "Object" : "12345678" , "Object2" : "87654321" } )");
+ test_cryptomatte_manifest(R"({"Object\"01\"":"12345678"})", R"({"Object\"01\"": "12345678"})");
test_cryptomatte_manifest(
- "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
- "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}");
+ R"({"Object\"01\"":"12345678","Object":"12345678","Object2":"87654321"})",
+ R"({"Object\"01\"":"12345678","Object":"12345678", "Object2":"87654321"})");
}
TEST(cryptomatte, extract_layer_hash_from_metadata_key)
@@ -127,7 +123,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data),
EXPECT_STREQ("uint32_to_float32", propvalue);
}
else if (prop_name == "cryptomatte/87f095e/manifest") {
- EXPECT_STREQ("{\"Object\":\"12345678\"}", propvalue);
+ EXPECT_STREQ(R"({"Object":"12345678"})", propvalue);
}
else if (prop_name == "cryptomatte/c42daa7/name") {
@@ -140,7 +136,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data),
EXPECT_STREQ("uint32_to_float32", propvalue);
}
else if (prop_name == "cryptomatte/c42daa7/manifest") {
- EXPECT_STREQ("{\"Object2\":\"87654321\"}", propvalue);
+ EXPECT_STREQ(R"({"Object2":"87654321"})", propvalue);
}
else {
@@ -155,12 +151,12 @@ TEST(cryptomatte, session_from_stamp_data)
MEM_callocN(sizeof(RenderResult), __func__));
BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1");
BKE_render_result_stamp_data(
- render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}");
+ render_result, "cryptomatte/qwerty/manifest", R"({"Object":"12345678"})");
BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2");
BKE_render_result_stamp_data(
- render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}");
- CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result);
- EXPECT_NE(session, nullptr);
+ render_result, "cryptomatte/uiop/manifest", R"({"Object2":"87654321"})");
+ CryptomatteSessionPtr session(BKE_cryptomatte_init_from_render_result(render_result));
+ EXPECT_NE(session.get(), nullptr);
RE_FreeRenderResult(render_result);
/* Create StampData from CryptomatteSession. */
@@ -168,25 +164,23 @@ TEST(cryptomatte, session_from_stamp_data)
BLI_strncpy(view_layer.name, "viewlayername", sizeof(view_layer.name));
RenderResult *render_result2 = static_cast<RenderResult *>(
MEM_callocN(sizeof(RenderResult), __func__));
- BKE_cryptomatte_store_metadata(session, render_result2, &view_layer);
+ BKE_cryptomatte_store_metadata(session.get(), render_result2, &view_layer);
/* Validate StampData. */
BKE_stamp_info_callback(
nullptr, render_result2->stamp_data, validate_cryptomatte_session_from_stamp_data, false);
RE_FreeRenderResult(render_result2);
- BKE_cryptomatte_free(session);
}
-TEST(cryptomatte, T86026)
+/**
+ * Test method that contains known malformed manifests and makes sure that these can be parsed as
+ * best as possible. */
+TEST(cryptomatte, parsing_malformed_manifests)
{
- NodeCryptomatte storage = {{0.0f}};
- CryptomatteEntry entry = {nullptr};
- BLI_addtail(&storage.entries, &entry);
- entry.encoded_hash = 4.76190593e-07;
- char *matte_id = BKE_cryptomatte_entries_to_matte_id(&storage);
- EXPECT_STREQ("<4.761905927e-07>", matte_id);
- MEM_freeN(matte_id);
+ /* Manifest from multilayer.exr in the cryptomatte git-repository. */
+ test_cryptomatte_manifest(
+ R"({"/obj/instance1:instances:0":"0d54c6cc","/obj/instance1:instances:1":"293d9340","/obj/instance1:instances:110":"ccb9e1f2","/obj/instance1:instances:111":"f8dd3a48","/obj/instance1:instances:112":"a99e07a8","/obj/instance1:instances:113":"e75599a4","/obj/instance1:instances:114":"794200f3","/obj/instance1:instances:115":"2a3a1728","/obj/instance1:instances:116":"478544a1","/obj/instance1:instances:117":"b2bd969a","/obj/instance1:instances:10":"3a0c8681","/obj/instance1:instances:11":"01e5970d","/obj/box:polygons:1":"9d416418","/obj/instance1:instances:100":"2dcd2966","/obj/instance1:instances:101":"9331cd82","/obj/instance1:instances:102":"df50fccb","/obj/instance1:instances:103":"97f8590d","/obj/instance1:instances:104":"bbcd220d","/obj/instance1:instances:105":"4ae06139","/obj/instance1:instances:106":"8873d5ea","/obj/instance1:instances:107":"39d8af8d","/obj/instance1:instances:108":"bb11bd4e","/obj/instance1:instances:109":"a32bba35"})",
+ R"({"\/obj\/box:polygons:1":"9d416418","\/obj\/instance1:instances:0":"0d54c6cc","\/obj\/instance1:instances:1":"293d9340","\/obj\/instance1:instances:10":"3a0c8681","\/obj\/instance1:instances:100":"2dcd2966","\/obj\/instance1:instances:101":"9331cd82","\/obj\/instance1:instances:102":"df50fccb","\/obj\/instance1:instances:103":"97f8590d","\/obj\/instance1:instances:104":"bbcd220d","\/obj\/instance1:instances:105":"4ae06139","\/obj\/instance1:instances:106":"8873d5ea","\/obj\/instance1:instances:107":"39d8af8d","\/obj\/instance1:instances:108":"bb11bd4e","\/obj\/instance1:instances:109":"a32bba35","\/obj\/instance1:instances:11":"01e5970d","\/obj\/instance1:instances:110":"ccb9e1f2","\/obj\/instance1:instances:111":"f8dd3a48","\/obj\/instance1:instances:112":"a99e07a8","\/obj\/instance1:instances:113":"e75599a4","\/obj\/instance1:instances:114":"794200f3","\/obj\/instance1:instances:115":"2a3a1728","\/obj\/instance1:instances:116":"478544a1","\/obj\/instance1:instances:117":"b2bd969a","\/obj\/instance1:instance)");
}
-
} // namespace blender::bke::cryptomatte::tests
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index c860e57520d..708b1971bd5 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -875,9 +875,9 @@ static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[
allverts = MEM_mallocN(sizeof(float[3]) * (*r_vert_len), "displist_vert_coords_alloc allverts");
fp = (float *)allverts;
LISTBASE_FOREACH (DispList *, dl, dispbase) {
- int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
- memcpy(fp, dl->verts, sizeof(float) * offs);
- fp += offs;
+ int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
+ memcpy(fp, dl->verts, sizeof(float) * ofs);
+ fp += ofs;
}
return allverts;
@@ -889,9 +889,9 @@ static void displist_vert_coords_apply(ListBase *dispbase, float (*allverts)[3])
fp = (float *)allverts;
LISTBASE_FOREACH (DispList *, dl, dispbase) {
- int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
- memcpy(dl->verts, fp, sizeof(float) * offs);
- fp += offs;
+ int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
+ memcpy(dl->verts, fp, sizeof(float) * ofs);
+ fp += ofs;
}
}
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
new file mode 100644
index 00000000000..68c551645d2
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -0,0 +1,173 @@
+/*
+ * 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_float4x4.hh"
+#include "BLI_map.hh"
+#include "BLI_rand.hh"
+#include "BLI_set.hh"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_collection_types.h"
+
+#include "BKE_geometry_set.hh"
+
+using blender::float4x4;
+using blender::Map;
+using blender::MutableSpan;
+using blender::Set;
+using blender::Span;
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+InstancesComponent::InstancesComponent() : GeometryComponent(GEO_COMPONENT_TYPE_INSTANCES)
+{
+}
+
+GeometryComponent *InstancesComponent::copy() const
+{
+ InstancesComponent *new_component = new InstancesComponent();
+ new_component->transforms_ = transforms_;
+ new_component->instanced_data_ = instanced_data_;
+ return new_component;
+}
+
+void InstancesComponent::clear()
+{
+ instanced_data_.clear();
+ transforms_.clear();
+}
+
+void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id)
+{
+ InstancedData data;
+ data.type = INSTANCE_DATA_TYPE_OBJECT;
+ data.data.object = object;
+ this->add_instance(data, transform, id);
+}
+
+void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id)
+{
+ InstancedData data;
+ data.type = INSTANCE_DATA_TYPE_COLLECTION;
+ data.data.collection = collection;
+ this->add_instance(data, transform, id);
+}
+
+void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id)
+{
+ instanced_data_.append(data);
+ transforms_.append(transform);
+ ids_.append(id);
+}
+
+Span<InstancedData> InstancesComponent::instanced_data() const
+{
+ return instanced_data_;
+}
+
+Span<float4x4> InstancesComponent::transforms() const
+{
+ return transforms_;
+}
+
+Span<int> InstancesComponent::ids() const
+{
+ return ids_;
+}
+
+MutableSpan<float4x4> InstancesComponent::transforms()
+{
+ return transforms_;
+}
+
+int InstancesComponent::instances_amount() const
+{
+ const int size = instanced_data_.size();
+ BLI_assert(transforms_.size() == size);
+ return size;
+}
+
+bool InstancesComponent::is_empty() const
+{
+ return transforms_.size() == 0;
+}
+
+static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+{
+ using namespace blender;
+ Array<int> unique_ids(original_ids.size());
+
+ Set<int> used_unique_ids;
+ used_unique_ids.reserve(original_ids.size());
+ Vector<int> instances_with_id_collision;
+ for (const int instance_index : original_ids.index_range()) {
+ const int original_id = original_ids[instance_index];
+ if (used_unique_ids.add(original_id)) {
+ /* The original id has not been used by another instance yet. */
+ unique_ids[instance_index] = original_id;
+ }
+ else {
+ /* The original id of this instance collided with a previous instance, it needs to be looked
+ * at again in a second pass. Don't generate a new random id here, because this might collide
+ * with other existing ids. */
+ instances_with_id_collision.append(instance_index);
+ }
+ }
+
+ Map<int, RandomNumberGenerator> generator_by_original_id;
+ for (const int instance_index : instances_with_id_collision) {
+ const int original_id = original_ids[instance_index];
+ RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
+ RandomNumberGenerator rng;
+ rng.seed_random(original_id);
+ return rng;
+ });
+
+ const int max_iteration = 100;
+ for (int iteration = 0;; iteration++) {
+ /* Try generating random numbers until an unused one has been found. */
+ const int random_id = rng.get_int32();
+ if (used_unique_ids.add(random_id)) {
+ /* This random id is not used by another instance. */
+ unique_ids[instance_index] = random_id;
+ break;
+ }
+ if (iteration == max_iteration) {
+ /* It seems to be very unlikely that we ever run into this case (assuming there are less
+ * than 2^30 instances). However, if that happens, it's better to use an id that is not
+ * unique than to be stuck in an infinite loop. */
+ unique_ids[instance_index] = original_id;
+ break;
+ }
+ }
+ }
+
+ return unique_ids;
+}
+
+blender::Span<int> InstancesComponent::almost_unique_ids() const
+{
+ std::lock_guard lock(almost_unique_ids_mutex_);
+ if (almost_unique_ids_.size() != ids_.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(ids_);
+ }
+ return almost_unique_ids_;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
new file mode 100644
index 00000000000..8ee2142799d
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -0,0 +1,979 @@
+/*
+ * 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_listbase.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "attribute_access_intern.hh"
+
+/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
+extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
+
+using blender::bke::ReadAttributePtr;
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+MeshComponent::MeshComponent() : GeometryComponent(GEO_COMPONENT_TYPE_MESH)
+{
+}
+
+MeshComponent::~MeshComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *MeshComponent::copy() const
+{
+ MeshComponent *new_component = new MeshComponent();
+ if (mesh_ != nullptr) {
+ new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ new_component->vertex_group_names_ = blender::Map(vertex_group_names_);
+ }
+ return new_component;
+}
+
+void MeshComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (mesh_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, mesh_);
+ }
+ mesh_ = nullptr;
+ }
+ vertex_group_names_.clear();
+}
+
+bool MeshComponent::has_mesh() const
+{
+ return mesh_ != nullptr;
+}
+
+/* Clear the component and replace it with the new mesh. */
+void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ mesh_ = mesh;
+ ownership_ = ownership;
+}
+
+/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to
+ * be able to replace the mesh data without losing the vertex group names, which may have come
+ * from another object. */
+void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh,
+ GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ if (mesh_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, mesh_);
+ }
+ mesh_ = nullptr;
+ }
+ mesh_ = mesh;
+ ownership_ = ownership;
+}
+
+/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
+ * mesh (if the component was responsible before). */
+Mesh *MeshComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Mesh *mesh = mesh_;
+ mesh_ = nullptr;
+ return mesh;
+}
+
+void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
+{
+ BLI_assert(this->is_mutable());
+ vertex_group_names_.clear();
+ int index = 0;
+ LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) {
+ vertex_group_names_.add(group->name, index);
+ index++;
+ }
+}
+
+const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const
+{
+ return vertex_group_names_;
+}
+
+/* This is only exposed for the internal attribute API. */
+blender::Map<std::string, int> &MeshComponent::vertex_group_names()
+{
+ return vertex_group_names_;
+}
+
+/* Get the mesh from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
+const Mesh *MeshComponent::get_for_read() const
+{
+ return mesh_;
+}
+
+/* Get the mesh from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
+Mesh *MeshComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return mesh_;
+}
+
+bool MeshComponent::is_empty() const
+{
+ return mesh_ == nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Access
+ * \{ */
+
+int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ BLI_assert(this->attribute_domain_supported(domain));
+ if (mesh_ == nullptr) {
+ return 0;
+ }
+ switch (domain) {
+ case ATTR_DOMAIN_CORNER:
+ return mesh_->totloop;
+ case ATTR_DOMAIN_POINT:
+ return mesh_->totvert;
+ case ATTR_DOMAIN_EDGE:
+ return mesh_->totedge;
+ case ATTR_DOMAIN_POLYGON:
+ return mesh_->totpoly;
+ default:
+ BLI_assert(false);
+ break;
+ }
+ return 0;
+}
+
+namespace blender::bke {
+
+template<typename T>
+static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
+ const TypedReadAttribute<T> &attribute,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int loop_index : IndexRange(mesh.totloop)) {
+ const T value = attribute[loop_index];
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+ mixer.mix_in(point_index, value);
+ }
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ /* We compute all interpolated values at once, because for this interpolation, one has to
+ * iterate over all loops anyway. */
+ Array<T> values(mesh.totvert);
+ adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
+ const TypedReadAttribute<T> &attribute,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totloop);
+
+ for (const int loop_index : IndexRange(mesh.totloop)) {
+ const int vertex_index = mesh.mloop[loop_index].v;
+ r_values[loop_index] = attribute[vertex_index];
+ }
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ /* It is not strictly necessary to compute the value for all corners here. Instead one could
+ * lazily lookup the mesh topology when a specific index accessed. This can be more efficient
+ * when an algorithm only accesses very few of the corner values. However, for the algorithms
+ * we currently have, precomputing the array is fine. Also, it is easier to implement. */
+ Array<T> values(mesh.totloop);
+ adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
+ std::move(values));
+ });
+ return new_attribute;
+}
+
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh,
+ Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const T value = old_values[loop_index];
+ mixer.mix_in(poly_index, value);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totpoly);
+ adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
+ Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const T value = old_values[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+ mixer.mix_in(point_index, value);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totvert);
+ adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totloop);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
+ poly_corner_values.fill(old_values[poly_index]);
+ }
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totloop);
+ adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+ mixer.mix_in(poly_index, old_values[point_index]);
+ }
+ }
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totpoly);
+ adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+} // namespace blender::bke
+
+ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
+ const AttributeDomain new_domain) const
+{
+ if (!attribute) {
+ return {};
+ }
+ if (attribute->size() == 0) {
+ return {};
+ }
+ const AttributeDomain old_domain = attribute->domain();
+ if (old_domain == new_domain) {
+ return attribute;
+ }
+
+ switch (old_domain) {
+ case ATTR_DOMAIN_CORNER: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_POINT:
+ return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_POLYGON:
+ return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
+ default:
+ break;
+ }
+ break;
+ }
+ case ATTR_DOMAIN_POINT: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_CORNER:
+ return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_POLYGON:
+ return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
+ default:
+ break;
+ }
+ break;
+ }
+ case ATTR_DOMAIN_POLYGON: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_POINT:
+ return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_CORNER:
+ return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return {};
+}
+
+static Mesh *get_mesh_from_component_for_write(GeometryComponent &component)
+{
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+ return mesh_component.get_for_write();
+}
+
+static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
+{
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return mesh_component.get_for_read();
+}
+
+namespace blender::bke {
+
+static float3 get_vertex_position(const MVert &vert)
+{
+ return float3(vert.co);
+}
+
+static void set_vertex_position(MVert &vert, const float3 &position)
+{
+ copy_v3_v3(vert.co, position);
+}
+
+static ReadAttributePtr make_vertex_position_read_attribute(const void *data,
+ const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>(
+ ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size));
+}
+
+static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>(
+ ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size));
+}
+
+static void tag_normals_dirty_when_writing_position(GeometryComponent &component)
+{
+ Mesh *mesh = get_mesh_from_component_for_write(component);
+ if (mesh != nullptr) {
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+}
+
+static int get_material_index(const MPoly &mpoly)
+{
+ return static_cast<int>(mpoly.mat_nr);
+}
+
+static void set_material_index(MPoly &mpoly, const int &index)
+{
+ mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
+}
+
+static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>(
+ ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
+}
+
+static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>(
+ ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
+}
+
+static bool get_shade_smooth(const MPoly &mpoly)
+{
+ return mpoly.flag & ME_SMOOTH;
+}
+
+static void set_shade_smooth(MPoly &mpoly, const bool &value)
+{
+ SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
+}
+
+static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>(
+ ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
+}
+
+static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>(
+ ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
+}
+
+static float2 get_loop_uv(const MLoopUV &uv)
+{
+ return float2(uv.uv);
+}
+
+static void set_loop_uv(MLoopUV &uv, const float2 &co)
+{
+ copy_v2_v2(uv.uv, co);
+}
+
+static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>(
+ ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size));
+}
+
+static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>(
+ ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size));
+}
+
+static Color4f get_loop_color(const MLoopCol &col)
+{
+ Color4f value;
+ rgba_uchar_to_float(value, &col.r);
+ return value;
+}
+
+static void set_loop_color(MLoopCol &col, const Color4f &value)
+{
+ rgba_float_to_uchar(&col.r, value);
+}
+
+static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>(
+ ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size));
+}
+
+static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>(
+ ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size));
+}
+
+static float get_crease(const MEdge &edge)
+{
+ return edge.crease / 255.0f;
+}
+
+static void set_crease(MEdge &edge, const float &value)
+{
+ edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
+}
+
+static ReadAttributePtr make_crease_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MEdge, float, get_crease>>(
+ ATTR_DOMAIN_EDGE, Span((const MEdge *)data, domain_size));
+}
+
+static WriteAttributePtr make_crease_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayWriteAttribute<MEdge, float, get_crease, set_crease>>(
+ ATTR_DOMAIN_EDGE, MutableSpan((MEdge *)data, domain_size));
+}
+
+class VertexWeightWriteAttribute final : public WriteAttribute {
+ private:
+ MDeformVert *dverts_;
+ const int dvert_index_;
+
+ public:
+ VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
+ : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
+ dverts_(dverts),
+ dvert_index_(dvert_index)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ get_internal(dverts_, dvert_index_, index, r_value);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
+ weight->weight = *reinterpret_cast<const float *>(value);
+ }
+
+ static void get_internal(const MDeformVert *dverts,
+ const int dvert_index,
+ const int64_t index,
+ void *r_value)
+ {
+ if (dverts == nullptr) {
+ *(float *)r_value = 0.0f;
+ return;
+ }
+ const MDeformVert &dvert = dverts[index];
+ for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
+ if (weight.def_nr == dvert_index) {
+ *(float *)r_value = weight.weight;
+ return;
+ }
+ }
+ *(float *)r_value = 0.0f;
+ }
+};
+
+class VertexWeightReadAttribute final : public ReadAttribute {
+ private:
+ const MDeformVert *dverts_;
+ const int dvert_index_;
+
+ public:
+ VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
+ : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
+ dverts_(dverts),
+ dvert_index_(dvert_index)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
+ }
+};
+
+/**
+ * This provider makes vertex groups available as float attributes.
+ */
+class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
+ public:
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final
+ {
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
+ attribute_name, -1);
+ if (vertex_group_index < 0) {
+ return {};
+ }
+ if (mesh == nullptr || mesh->dvert == nullptr) {
+ static const float default_value = 0.0f;
+ return std::make_unique<ConstantReadAttribute>(
+ ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
+ }
+ return std::make_unique<VertexWeightReadAttribute>(
+ mesh->dvert, mesh->totvert, vertex_group_index);
+ }
+
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final
+ {
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+ Mesh *mesh = mesh_component.get_for_write();
+ if (mesh == nullptr) {
+ return {};
+ }
+ const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
+ attribute_name, -1);
+ if (vertex_group_index < 0) {
+ return {};
+ }
+ if (mesh->dvert == nullptr) {
+ BKE_object_defgroup_data_create(&mesh->id);
+ }
+ else {
+ /* Copy the data layer if it is shared with some other mesh. */
+ mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
+ &mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
+ }
+ return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
+ mesh->dvert, mesh->totvert, vertex_group_index);
+ }
+
+ bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
+ {
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+
+ const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as(
+ attribute_name, -1);
+ if (vertex_group_index < 0) {
+ return false;
+ }
+ Mesh *mesh = mesh_component.get_for_write();
+ if (mesh == nullptr) {
+ return true;
+ }
+ if (mesh->dvert == nullptr) {
+ return true;
+ }
+ for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
+ MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
+ BKE_defvert_remove_group(&dvert, weight);
+ }
+ return true;
+ }
+
+ bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const final
+ {
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ for (const auto item : mesh_component.vertex_group_names().items()) {
+ const StringRefNull name = item.key;
+ const int vertex_group_index = item.value;
+ if (vertex_group_index >= 0) {
+ AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT};
+ if (!callback(name, meta_data)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ {
+ callback(ATTR_DOMAIN_POINT);
+ }
+};
+
+/**
+ * This provider makes face normals available as a read-only float3 attribute.
+ */
+class NormalAttributeProvider final : public BuiltinAttributeProvider {
+ public:
+ NormalAttributeProvider()
+ : BuiltinAttributeProvider(
+ "normal", ATTR_DOMAIN_POLYGON, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
+ {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ /* Use existing normals if possible. */
+ if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
+ CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+
+ return std::make_unique<ArrayReadAttribute<float3>>(
+ ATTR_DOMAIN_POLYGON, Span<float3>((const float3 *)data, mesh->totpoly));
+ }
+
+ Array<float3> normals(mesh->totpoly);
+ for (const int i : IndexRange(mesh->totpoly)) {
+ const MPoly *poly = &mesh->mpoly[i];
+ BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
+ }
+
+ return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_POLYGON,
+ std::move(normals));
+ }
+
+ WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ {
+ return {};
+ }
+
+ bool try_delete(GeometryComponent &UNUSED(component)) const final
+ {
+ return false;
+ }
+
+ bool try_create(GeometryComponent &UNUSED(component)) const final
+ {
+ return false;
+ }
+
+ bool exists(const GeometryComponent &component) const final
+ {
+ return component.attribute_domain_size(ATTR_DOMAIN_POLYGON) != 0;
+ }
+};
+
+/**
+ * In this function all the attribute providers for a mesh component are created. Most data in this
+ * function is statically allocated, because it does not change over time.
+ */
+static ComponentAttributeProviders create_attribute_providers_for_mesh()
+{
+ static auto update_custom_data_pointers = [](GeometryComponent &component) {
+ Mesh *mesh = get_mesh_from_component_for_write(component);
+ if (mesh != nullptr) {
+ BKE_mesh_update_customdata_pointers(mesh, false);
+ }
+ };
+
+#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
+ [](GeometryComponent &component) -> CustomData * { \
+ Mesh *mesh = get_mesh_from_component_for_write(component); \
+ return mesh ? &mesh->NAME : nullptr; \
+ }
+#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
+ [](const GeometryComponent &component) -> const CustomData * { \
+ const Mesh *mesh = get_mesh_from_component_for_read(component); \
+ return mesh ? &mesh->NAME : nullptr; \
+ }
+
+ static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(ldata),
+ update_custom_data_pointers};
+ static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(vdata),
+ update_custom_data_pointers};
+ static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(edata),
+ update_custom_data_pointers};
+ static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
+ update_custom_data_pointers};
+
+#undef MAKE_CONST_CUSTOM_DATA_GETTER
+#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
+
+ static BuiltinCustomDataLayerProvider position("position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_MVERT,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_vertex_position_read_attribute,
+ make_vertex_position_write_attribute,
+ tag_normals_dirty_when_writing_position);
+
+ static NormalAttributeProvider normal;
+
+ static BuiltinCustomDataLayerProvider material_index("material_index",
+ ATTR_DOMAIN_POLYGON,
+ CD_PROP_INT32,
+ CD_MPOLY,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ polygon_access,
+ make_material_index_read_attribute,
+ make_material_index_write_attribute,
+ nullptr);
+
+ static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth",
+ ATTR_DOMAIN_POLYGON,
+ CD_PROP_BOOL,
+ CD_MPOLY,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ polygon_access,
+ make_shade_smooth_read_attribute,
+ make_shade_smooth_write_attribute,
+ nullptr);
+
+ static BuiltinCustomDataLayerProvider crease("crease",
+ ATTR_DOMAIN_EDGE,
+ CD_PROP_FLOAT,
+ CD_MEDGE,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ edge_access,
+ make_crease_read_attribute,
+ make_crease_write_attribute,
+ nullptr);
+
+ static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER,
+ CD_PROP_FLOAT2,
+ CD_MLOOPUV,
+ corner_access,
+ make_uvs_read_attribute,
+ make_uvs_write_attribute);
+
+ static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER,
+ CD_PROP_COLOR,
+ CD_MLOOPCOL,
+ corner_access,
+ make_vertex_color_read_attribute,
+ make_vertex_color_write_attribute);
+
+ static VertexGroupsAttributeProvider vertex_groups;
+ static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
+ static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
+ static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
+ static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access);
+
+ return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease},
+ {&uvs,
+ &vertex_colors,
+ &corner_custom_data,
+ &vertex_groups,
+ &point_custom_data,
+ &edge_custom_data,
+ &polygon_custom_data});
+}
+
+} // namespace blender::bke
+
+const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
+{
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_mesh();
+ return &providers;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
new file mode 100644
index 00000000000..073f457ae54
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -0,0 +1,205 @@
+/*
+ * 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 "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_access.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_pointcloud.h"
+
+#include "attribute_access_intern.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+PointCloudComponent::PointCloudComponent() : GeometryComponent(GEO_COMPONENT_TYPE_POINT_CLOUD)
+{
+}
+
+PointCloudComponent::~PointCloudComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *PointCloudComponent::copy() const
+{
+ PointCloudComponent *new_component = new PointCloudComponent();
+ if (pointcloud_ != nullptr) {
+ new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void PointCloudComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (pointcloud_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, pointcloud_);
+ }
+ pointcloud_ = nullptr;
+ }
+}
+
+bool PointCloudComponent::has_pointcloud() const
+{
+ return pointcloud_ != nullptr;
+}
+
+/* Clear the component and replace it with the new point cloud. */
+void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ pointcloud_ = pointcloud;
+ ownership_ = ownership;
+}
+
+/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
+ * the point cloud (if the component was responsible before). */
+PointCloud *PointCloudComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ PointCloud *pointcloud = pointcloud_;
+ pointcloud_ = nullptr;
+ return pointcloud;
+}
+
+/* Get the point cloud from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
+ */
+const PointCloud *PointCloudComponent::get_for_read() const
+{
+ return pointcloud_;
+}
+
+/* Get the point cloud from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
+ * transferred. */
+PointCloud *PointCloudComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return pointcloud_;
+}
+
+bool PointCloudComponent::is_empty() const
+{
+ return pointcloud_ == nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Access
+ * \{ */
+
+int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ BLI_assert(domain == ATTR_DOMAIN_POINT);
+ UNUSED_VARS_NDEBUG(domain);
+ if (pointcloud_ == nullptr) {
+ return 0;
+ }
+ return pointcloud_->totpoint;
+}
+
+namespace blender::bke {
+
+template<typename T, AttributeDomain Domain>
+static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+}
+
+template<typename T, AttributeDomain Domain>
+static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
+}
+
+/**
+ * In this function all the attribute providers for a point cloud component are created. Most data
+ * in this function is statically allocated, because it does not change over time.
+ */
+static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
+{
+ static auto update_custom_data_pointers = [](GeometryComponent &component) {
+ PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
+ PointCloud *pointcloud = pointcloud_component.get_for_write();
+ if (pointcloud != nullptr) {
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+ }
+ };
+ static CustomDataAccessInfo point_access = {
+ [](GeometryComponent &component) -> CustomData * {
+ PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
+ PointCloud *pointcloud = pointcloud_component.get_for_write();
+ return pointcloud ? &pointcloud->pdata : nullptr;
+ },
+ [](const GeometryComponent &component) -> const CustomData * {
+ const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
+ component);
+ const PointCloud *pointcloud = pointcloud_component.get_for_read();
+ return pointcloud ? &pointcloud->pdata : nullptr;
+ },
+ update_custom_data_pointers};
+
+ static BuiltinCustomDataLayerProvider position(
+ "position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
+ make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
+ nullptr);
+ static BuiltinCustomDataLayerProvider radius(
+ "radius",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
+ make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
+ nullptr);
+ static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
+ return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
+}
+
+} // namespace blender::bke
+
+const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
+ const
+{
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_point_cloud();
+ return &providers;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc
new file mode 100644
index 00000000000..fd2327e0bf5
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_volume.cc
@@ -0,0 +1,100 @@
+/*
+ * 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 "DNA_volume_types.h"
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_volume.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+VolumeComponent::VolumeComponent() : GeometryComponent(GEO_COMPONENT_TYPE_VOLUME)
+{
+}
+
+VolumeComponent::~VolumeComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *VolumeComponent::copy() const
+{
+ VolumeComponent *new_component = new VolumeComponent();
+ if (volume_ != nullptr) {
+ new_component->volume_ = BKE_volume_copy_for_eval(volume_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void VolumeComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (volume_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, volume_);
+ }
+ volume_ = nullptr;
+ }
+}
+
+bool VolumeComponent::has_volume() const
+{
+ return volume_ != nullptr;
+}
+
+/* Clear the component and replace it with the new volume. */
+void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ volume_ = volume;
+ ownership_ = ownership;
+}
+
+/* Return the volume and clear the component. The caller takes over responsibility for freeing the
+ * volume (if the component was responsible before). */
+Volume *VolumeComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Volume *volume = volume_;
+ volume_ = nullptr;
+ return volume;
+}
+
+/* Get the volume from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
+const Volume *VolumeComponent::get_for_read() const
+{
+ return volume_;
+}
+
+/* Get the volume from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
+Volume *VolumeComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ volume_ = BKE_volume_copy_for_eval(volume_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return volume_;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 0274dfdbd1c..f47d88cbeed 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -56,13 +56,13 @@ GeometryComponent ::~GeometryComponent()
GeometryComponent *GeometryComponent::create(GeometryComponentType component_type)
{
switch (component_type) {
- case GeometryComponentType::Mesh:
+ case GEO_COMPONENT_TYPE_MESH:
return new MeshComponent();
- case GeometryComponentType::PointCloud:
+ case GEO_COMPONENT_TYPE_POINT_CLOUD:
return new PointCloudComponent();
- case GeometryComponentType::Instances:
+ case GEO_COMPONENT_TYPE_INSTANCES:
return new InstancesComponent();
- case GeometryComponentType::Volume:
+ case GEO_COMPONENT_TYPE_VOLUME:
return new VolumeComponent();
}
BLI_assert(false);
@@ -311,437 +311,6 @@ Volume *GeometrySet::get_volume_for_write()
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh Component
- * \{ */
-
-MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh)
-{
-}
-
-MeshComponent::~MeshComponent()
-{
- this->clear();
-}
-
-GeometryComponent *MeshComponent::copy() const
-{
- MeshComponent *new_component = new MeshComponent();
- if (mesh_ != nullptr) {
- new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- new_component->vertex_group_names_ = blender::Map(vertex_group_names_);
- }
- return new_component;
-}
-
-void MeshComponent::clear()
-{
- BLI_assert(this->is_mutable());
- if (mesh_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, mesh_);
- }
- mesh_ = nullptr;
- }
- vertex_group_names_.clear();
-}
-
-bool MeshComponent::has_mesh() const
-{
- return mesh_ != nullptr;
-}
-
-/* Clear the component and replace it with the new mesh. */
-void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- mesh_ = mesh;
- ownership_ = ownership;
-}
-
-/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to
- * be able to replace the mesh data without losing the vertex group names, which may have come
- * from another object. */
-void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh,
- GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- if (mesh_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, mesh_);
- }
- mesh_ = nullptr;
- }
- mesh_ = mesh;
- ownership_ = ownership;
-}
-
-/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
- * mesh (if the component was responsible before). */
-Mesh *MeshComponent::release()
-{
- BLI_assert(this->is_mutable());
- Mesh *mesh = mesh_;
- mesh_ = nullptr;
- return mesh;
-}
-
-void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
-{
- BLI_assert(this->is_mutable());
- vertex_group_names_.clear();
- int index = 0;
- LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) {
- vertex_group_names_.add(group->name, index);
- index++;
- }
-}
-
-const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const
-{
- return vertex_group_names_;
-}
-
-/* This is only exposed for the internal attribute API. */
-blender::Map<std::string, int> &MeshComponent::vertex_group_names()
-{
- return vertex_group_names_;
-}
-
-/* Get the mesh from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
-const Mesh *MeshComponent::get_for_read() const
-{
- return mesh_;
-}
-
-/* Get the mesh from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
-Mesh *MeshComponent::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return mesh_;
-}
-
-bool MeshComponent::is_empty() const
-{
- return mesh_ == nullptr;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Pointcloud Component
- * \{ */
-
-PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud)
-{
-}
-
-PointCloudComponent::~PointCloudComponent()
-{
- this->clear();
-}
-
-GeometryComponent *PointCloudComponent::copy() const
-{
- PointCloudComponent *new_component = new PointCloudComponent();
- if (pointcloud_ != nullptr) {
- new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- }
- return new_component;
-}
-
-void PointCloudComponent::clear()
-{
- BLI_assert(this->is_mutable());
- if (pointcloud_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, pointcloud_);
- }
- pointcloud_ = nullptr;
- }
-}
-
-bool PointCloudComponent::has_pointcloud() const
-{
- return pointcloud_ != nullptr;
-}
-
-/* Clear the component and replace it with the new point cloud. */
-void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- pointcloud_ = pointcloud;
- ownership_ = ownership;
-}
-
-/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
- * the point cloud (if the component was responsible before). */
-PointCloud *PointCloudComponent::release()
-{
- BLI_assert(this->is_mutable());
- PointCloud *pointcloud = pointcloud_;
- pointcloud_ = nullptr;
- return pointcloud;
-}
-
-/* Get the point cloud from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
- */
-const PointCloud *PointCloudComponent::get_for_read() const
-{
- return pointcloud_;
-}
-
-/* Get the point cloud from this component. This method can only be used when the component is
- * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
- * transferred. */
-PointCloud *PointCloudComponent::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return pointcloud_;
-}
-
-bool PointCloudComponent::is_empty() const
-{
- return pointcloud_ == nullptr;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Instances Component
- * \{ */
-
-InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances)
-{
-}
-
-GeometryComponent *InstancesComponent::copy() const
-{
- InstancesComponent *new_component = new InstancesComponent();
- new_component->transforms_ = transforms_;
- new_component->instanced_data_ = instanced_data_;
- return new_component;
-}
-
-void InstancesComponent::clear()
-{
- instanced_data_.clear();
- transforms_.clear();
-}
-
-void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id)
-{
- InstancedData data;
- data.type = INSTANCE_DATA_TYPE_OBJECT;
- data.data.object = object;
- this->add_instance(data, transform, id);
-}
-
-void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id)
-{
- InstancedData data;
- data.type = INSTANCE_DATA_TYPE_COLLECTION;
- data.data.collection = collection;
- this->add_instance(data, transform, id);
-}
-
-void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id)
-{
- instanced_data_.append(data);
- transforms_.append(transform);
- ids_.append(id);
-}
-
-Span<InstancedData> InstancesComponent::instanced_data() const
-{
- return instanced_data_;
-}
-
-Span<float4x4> InstancesComponent::transforms() const
-{
- return transforms_;
-}
-
-Span<int> InstancesComponent::ids() const
-{
- return ids_;
-}
-
-MutableSpan<float4x4> InstancesComponent::transforms()
-{
- return transforms_;
-}
-
-int InstancesComponent::instances_amount() const
-{
- const int size = instanced_data_.size();
- BLI_assert(transforms_.size() == size);
- return size;
-}
-
-bool InstancesComponent::is_empty() const
-{
- return transforms_.size() == 0;
-}
-
-static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
-{
- using namespace blender;
- Array<int> unique_ids(original_ids.size());
-
- Set<int> used_unique_ids;
- used_unique_ids.reserve(original_ids.size());
- Vector<int> instances_with_id_collision;
- for (const int instance_index : original_ids.index_range()) {
- const int original_id = original_ids[instance_index];
- if (used_unique_ids.add(original_id)) {
- /* The original id has not been used by another instance yet. */
- unique_ids[instance_index] = original_id;
- }
- else {
- /* The original id of this instance collided with a previous instance, it needs to be looked
- * at again in a second pass. Don't generate a new random id here, because this might collide
- * with other existing ids. */
- instances_with_id_collision.append(instance_index);
- }
- }
-
- Map<int, RandomNumberGenerator> generator_by_original_id;
- for (const int instance_index : instances_with_id_collision) {
- const int original_id = original_ids[instance_index];
- RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
- RandomNumberGenerator rng;
- rng.seed_random(original_id);
- return rng;
- });
-
- const int max_iteration = 100;
- for (int iteration = 0;; iteration++) {
- /* Try generating random numbers until an unused one has been found. */
- const int random_id = rng.get_int32();
- if (used_unique_ids.add(random_id)) {
- /* This random id is not used by another instance. */
- unique_ids[instance_index] = random_id;
- break;
- }
- if (iteration == max_iteration) {
- /* It seems to be very unlikely that we ever run into this case (assuming there are less
- * than 2^30 instances). However, if that happens, it's better to use an id that is not
- * unique than to be stuck in an infinite loop. */
- unique_ids[instance_index] = original_id;
- break;
- }
- }
- }
-
- return unique_ids;
-}
-
-blender::Span<int> InstancesComponent::almost_unique_ids() const
-{
- std::lock_guard lock(almost_unique_ids_mutex_);
- if (almost_unique_ids_.size() != ids_.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(ids_);
- }
- return almost_unique_ids_;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Volume Component
- * \{ */
-
-VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume)
-{
-}
-
-VolumeComponent::~VolumeComponent()
-{
- this->clear();
-}
-
-GeometryComponent *VolumeComponent::copy() const
-{
- VolumeComponent *new_component = new VolumeComponent();
- if (volume_ != nullptr) {
- new_component->volume_ = BKE_volume_copy_for_eval(volume_, false);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- }
- return new_component;
-}
-
-void VolumeComponent::clear()
-{
- BLI_assert(this->is_mutable());
- if (volume_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, volume_);
- }
- volume_ = nullptr;
- }
-}
-
-bool VolumeComponent::has_volume() const
-{
- return volume_ != nullptr;
-}
-
-/* Clear the component and replace it with the new volume. */
-void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- volume_ = volume;
- ownership_ = ownership;
-}
-
-/* Return the volume and clear the component. The caller takes over responsibility for freeing the
- * volume (if the component was responsible before). */
-Volume *VolumeComponent::release()
-{
- BLI_assert(this->is_mutable());
- Volume *volume = volume_;
- volume_ = nullptr;
- return volume;
-}
-
-/* Get the volume from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
-const Volume *VolumeComponent::get_for_read() const
-{
- return volume_;
-}
-
-/* Get the volume from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
-Volume *VolumeComponent::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- volume_ = BKE_volume_copy_for_eval(volume_, false);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return volume_;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name C API
* \{ */
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 1a260c5d48e..ce54ec7911f 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -371,14 +371,17 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
dst_component.replace(new_mesh);
Vector<GeometryComponentType> component_types;
- component_types.append(GeometryComponentType::Mesh);
+ component_types.append(GEO_COMPONENT_TYPE_MESH);
if (convert_points_to_vertices) {
- component_types.append(GeometryComponentType::PointCloud);
+ component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
}
/* Don't copy attributes that are stored directly in the mesh data structs. */
Map<std::string, AttributeKind> attributes;
- gather_attribute_info(attributes, component_types, set_groups, {"position", "material_index"});
+ gather_attribute_info(attributes,
+ component_types,
+ set_groups,
+ {"position", "material_index", "normal", "shade_smooth", "crease"});
join_attributes(
set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component));
}
@@ -399,9 +402,9 @@ static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_grou
PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
dst_component.replace(pointcloud);
Map<std::string, AttributeKind> attributes;
- gather_attribute_info(attributes, {GeometryComponentType::PointCloud}, set_groups, {});
+ gather_attribute_info(attributes, {GEO_COMPONENT_TYPE_POINT_CLOUD}, set_groups, {});
join_attributes(set_groups,
- {GeometryComponentType::PointCloud},
+ {GEO_COMPONENT_TYPE_POINT_CLOUD},
attributes,
static_cast<GeometryComponent &>(dst_component));
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 00dcaad83db..3b46672f9cd 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -1663,6 +1663,31 @@ bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd)
return NULL;
}
+bGPDlayer *BKE_gpencil_layer_get_by_name(bGPdata *gpd, char *name, int first_if_not_found)
+{
+ bGPDlayer *gpl;
+ int i = 0;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->layers.first)) {
+ return NULL;
+ }
+
+ /* loop over layers until found (assume only one active) */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (STREQ(name, gpl->info)) {
+ return gpl;
+ }
+ i++;
+ }
+
+ /* no such layer */
+ if (first_if_not_found) {
+ return gpd->layers.first;
+ }
+ return NULL;
+}
+
/**
* Set active grease pencil layer.
* \param gpd: Grease pencil data-block
@@ -2421,6 +2446,21 @@ int BKE_gpencil_object_material_index_get(Object *ob, Material *ma)
return -1;
}
+int BKE_gpencil_object_material_get_index_name(Object *ob, char *name)
+{
+ short *totcol = BKE_object_material_len_p(ob);
+ Material *read_ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ read_ma = BKE_object_material_get(ob, i + 1);
+ /* Material names are like "MAMaterial.001" */
+ if (STREQ(name, &read_ma->id.name[2])) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
/**
* Create a default palette.
* \param bmain: Main pointer
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index 1889d1c4eb0..fee70922570 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -63,7 +63,7 @@ bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v)
(key_a->offset_in_ID != key_b->offset_in_ID) || (key_a->cache_v != key_b->cache_v);
}
-static IDTypeInfo *id_types[MAX_LIBARRAY] = {NULL};
+static IDTypeInfo *id_types[INDEX_ID_MAX] = {NULL};
static void id_type_init(void)
{
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 54c2f5f5565..af921307bfb 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -171,7 +171,9 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
/* Conceptually, an ID made local is not the same as the linked one anymore. Reflect that by
* regenerating its session UUID. */
- BKE_lib_libblock_session_uuid_renew(id);
+ if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
* ones are two completely different data-blocks that were virtually remapped, even though in
@@ -916,7 +918,7 @@ void BKE_main_id_tag_idcode(struct Main *mainvar,
*/
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a;
a = set_listbasepointers(mainvar, lbarray);
@@ -949,7 +951,7 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
*/
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a;
a = set_listbasepointers(bmain, lbarray);
while (a--) {
@@ -1139,6 +1141,7 @@ static uint global_session_uuid = 0;
void BKE_lib_libblock_session_uuid_ensure(ID *id)
{
if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
+ BLI_assert((id->tag & LIB_TAG_TEMP_MAIN) == 0); /* Caller must ensure this. */
id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1);
/* In case overflow happens, still assign a valid ID. This way opening files many times works
* correctly. */
@@ -1870,7 +1873,7 @@ void BKE_library_make_local(Main *bmain,
const bool untagged_only,
const bool set_fake)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 7c5032c97f4..67b2e4429d6 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -240,7 +240,7 @@ void BKE_id_free_us(Main *bmain, void *idv) /* test users */
static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
{
const int tag = LIB_TAG_DOIT;
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
Link dummy_link = {0};
int base_count, i;
@@ -300,11 +300,15 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* links, this can lead to nasty crashing here in second, actual deleting loop.
* Also, this will also flag users of deleted data that cannot be unlinked
* (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(
- bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ BKE_libblock_remap_locked(bmain,
+ id,
+ NULL,
+ (ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
/* Since we removed ID from Main,
* we also need to unlink its own other IDs usages ourself. */
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS);
}
}
@@ -337,8 +341,12 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* actual deleting loop.
* Also, this will also flag users of deleted data that cannot be unlinked
* (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(
- bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ BKE_libblock_remap_locked(bmain,
+ id,
+ NULL,
+ (ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
}
}
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 602c560cedd..4ec130f8388 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <string.h>
+#include "CLG_log.h"
+
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
@@ -46,6 +48,7 @@
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "BLI_ghash.h"
@@ -66,6 +69,8 @@
# include "PIL_time_utildefines.h"
#endif
+static CLG_LogRef LOG = {"bke.liboverride"};
+
static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
IDOverrideLibraryProperty *op_src);
static void lib_override_library_property_operation_copy(
@@ -213,6 +218,32 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
return local_id;
}
+/** Check if given ID has some override rules that actually indicate the user edited it.
+ *
+ * TODO: This could be simplified by storing a flag in IDOverrideLibrary during the diffing
+ * process? */
+bool BKE_lib_override_library_is_user_edited(struct ID *id)
+{
+ if (!ID_IS_OVERRIDE_LIBRARY(id)) {
+ return false;
+ }
+
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
+ continue;
+ }
+ if (opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
+ continue;
+ }
+ /* If an operation does not match the filters above, it is considered as a user-editing one,
+ * therefore this override is user-edited. */
+ return true;
+ }
+ }
+ return false;
+}
+
/** Create an overridden local copy of linked reference. */
ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
@@ -379,7 +410,7 @@ typedef struct LibOverrideGroupTagData {
*
* Requires existing `Main.relations`.
*
- * Note: this is typically called to complete `lib_override_linked_group_tag()`.
+ * NOTE: This is typically called to complete `lib_override_linked_group_tag()`.
*/
static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTagData *data)
{
@@ -615,58 +646,85 @@ static bool lib_override_library_create_do(Main *bmain, ID *id_root)
return BKE_lib_override_library_create_from_tag(bmain);
}
-static void lib_override_library_create_post_process(
- Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, ID *id_reference)
+BLI_INLINE bool lib_override_library_create_post_process_object_is_instantiated(
+ ViewLayer *view_layer, Object *object, const bool is_resync)
+{
+ /* We cannot rely on check for object being actually instantiated in resync case, because often
+ * the overridden collection is 'excluded' from the current viewlayer.
+ *
+ * Fallback to a basic usercount check then, this is weak (since it could lead to some object not
+ * being instantiated at all), but it should work fine in most common cases. */
+ return ((is_resync && ID_REAL_USERS(object) >= 1) ||
+ (!is_resync && BKE_view_layer_base_find(view_layer, object) != NULL));
+}
+
+static void lib_override_library_create_post_process(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID *id_root,
+ ID *id_reference,
+ const bool is_resync)
{
BKE_main_collection_sync(bmain);
- switch (GS(id_root->name)) {
- case ID_GR: {
- Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
- (Object *)id_reference :
- NULL;
- Collection *collection_new = ((Collection *)id_root->newid);
- if (ob_reference != NULL) {
- BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
- }
- else if (id_reference != NULL) {
- BKE_collection_add_from_collection(
- bmain, scene, ((Collection *)id_reference), collection_new);
- }
- else {
- BKE_collection_add_from_collection(bmain, scene, ((Collection *)id_root), collection_new);
- }
+ if (id_root->newid != NULL) {
+ switch (GS(id_root->name)) {
+ case ID_GR: {
+ Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
+ (Object *)id_reference :
+ NULL;
+ Collection *collection_new = ((Collection *)id_root->newid);
+ if (ob_reference != NULL) {
+ BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
+ }
+ else if (id_reference != NULL) {
+ BLI_assert(GS(id_reference->name) == ID_GR);
+ BKE_collection_add_from_collection(
+ bmain, scene, ((Collection *)id_reference), collection_new);
+ }
+ else {
+ BKE_collection_add_from_collection(
+ bmain, scene, ((Collection *)id_root), collection_new);
+ }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) {
- if (ob_new != NULL && ob_new->id.override_library != NULL) {
- if (ob_reference != NULL) {
- Base *base;
- if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) {
- BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new);
- base = BKE_view_layer_base_find(view_layer, ob_new);
- DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
- }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) {
+ if (ob_new != NULL && ob_new->id.override_library != NULL) {
+ if (ob_reference != NULL) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob_new);
+ if (!lib_override_library_create_post_process_object_is_instantiated(
+ view_layer, ob_new, is_resync)) {
+ BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new);
+ base = BKE_view_layer_base_find(view_layer, ob_new);
+ DEG_id_tag_update_ex(
+ bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
+ }
- if (ob_new == (Object *)ob_reference->id.newid) {
- /* TODO: is setting active needed? */
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ if (ob_new == (Object *)ob_reference->id.newid && base != NULL) {
+ /* TODO: is setting active needed? */
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ }
+ }
+ else if (!lib_override_library_create_post_process_object_is_instantiated(
+ view_layer, ob_new, is_resync)) {
+ BKE_collection_object_add(bmain, collection_new, ob_new);
+ DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
}
- }
- else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) {
- BKE_collection_object_add(bmain, collection_new, ob_new);
- DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ break;
}
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- break;
- }
- case ID_OB: {
- BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ((Object *)id_root->newid));
- break;
+ case ID_OB: {
+ Object *ob_new = (Object *)id_root->newid;
+ if (!lib_override_library_create_post_process_object_is_instantiated(
+ view_layer, ob_new, is_resync)) {
+ BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
+ }
+ break;
+ }
+ default:
+ break;
}
- default:
- break;
}
/* We need to ensure all new overrides of objects are properly instantiated. */
@@ -677,7 +735,8 @@ static void lib_override_library_create_post_process(
ob_new->id.override_library->reference == &ob->id);
Collection *default_instantiating_collection = NULL;
- if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) {
+ if (!lib_override_library_create_post_process_object_is_instantiated(
+ view_layer, ob_new, is_resync)) {
if (default_instantiating_collection == NULL) {
switch (GS(id_root->name)) {
case ID_GR: {
@@ -740,7 +799,7 @@ bool BKE_lib_override_library_create(
return success;
}
- lib_override_library_create_post_process(bmain, scene, view_layer, id_root, id_reference);
+ lib_override_library_create_post_process(bmain, scene, view_layer, id_root, id_reference, false);
/* Cleanup. */
BKE_main_id_clear_newpoins(bmain);
@@ -799,7 +858,8 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
* \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)
+bool BKE_lib_override_library_resync(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, const bool do_hierarchy_enforce)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -879,6 +939,8 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
ID *id_override_new = id->newid;
ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
+
if (id_override_old != NULL) {
/* Swap the names between old override ID and new one. */
char id_name_buf[MAX_ID_NAME];
@@ -946,8 +1008,14 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
}
- RNA_struct_override_apply(
- bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library);
+ RNA_struct_override_apply(bmain,
+ &rnaptr_dst,
+ &rnaptr_src,
+ NULL,
+ id_override_new->override_library,
+ do_hierarchy_enforce ?
+ RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS :
+ RNA_OVERRIDE_APPLY_FLAG_NOP);
}
}
}
@@ -971,11 +1039,21 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
id->tag &= ~LIB_TAG_DOIT;
}
- /* Also cleanup old overrides that went missing in new linked data. */
+ /* Also deal with old overrides that went missing in new linked data. */
else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) {
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id));
- id->tag |= LIB_TAG_DOIT;
- id->tag &= ~LIB_TAG_MISSING;
+ if (!BKE_lib_override_library_is_user_edited(id)) {
+ /* If user never edited them, we can delete them. */
+ id->tag |= LIB_TAG_DOIT;
+ id->tag &= ~LIB_TAG_MISSING;
+ CLOG_INFO(&LOG, 2, "Old override %s is being deleted", id->name);
+ }
+ else {
+ /* Otherwise, keep them, user needs to decide whether what to do with them. */
+ BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
+ id_fake_user_set(id);
+ CLOG_INFO(&LOG, 2, "Old override %s is being kept around as it was user-edited", id->name);
+ }
}
}
FOREACH_MAIN_ID_END;
@@ -991,7 +1069,8 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
* since we already relinked old root override collection to new resync'ed one above. So this
* call is not expected to instantiate this new resync'ed collection anywhere, just to ensure
* that we do not have any stray objects. */
- lib_override_library_create_post_process(bmain, scene, view_layer, id_root_reference, id_root);
+ lib_override_library_create_post_process(
+ bmain, scene, view_layer, id_root_reference, id_root, true);
/* Cleanup. */
BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
@@ -1003,6 +1082,120 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
/**
+ * Detect and handle required resync of overrides data, when relations between reference linked IDs
+ * have changed.
+ *
+ * This is a fairly complex and costly operation, typically it should be called after
+ * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
+ *
+ * This function will first detect the remaining cases requiring a resync (namely, either when an
+ * existing linked ID that did not require to be overridden before now would be, or when new IDs
+ * are added to the hierarchy).
+ *
+ * Then it will handle the resync of necessary IDs (through calls to
+ * #BKE_lib_override_library_resync).
+ */
+void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *view_layer)
+{
+ BKE_main_relations_create(bmain, 0);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* NOTE: in code below, the order in which `FOREACH_MAIN_ID_BEGIN` processes ID types ensures
+ * that we always process 'higher-level' overrides first (i.e. scenes, then collections, then
+ * objects, then other types). */
+
+ /* Detect all linked data that would need to be overridden if we had to create an override from
+ * those used by current existing overrides. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ continue;
+ }
+ if (id->tag & (LIB_TAG_DOIT | LIB_TAG_MISSING)) {
+ /* We already processed that ID as part of another ID's hierarchy. */
+ continue;
+ }
+
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .id_root = id->override_library->reference,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING};
+ lib_override_linked_group_tag(&data);
+ BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
+ lib_override_hierarchy_dependencies_recursive_tag(&data);
+ BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Now check existing overrides, those needing resync will be the one either already tagged as
+ * such, or the one using linked data that is now tagged as needing override. */
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ continue;
+ }
+
+ if (id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) {
+ CLOG_INFO(&LOG, 4, "ID %s was already tagged as needing resync", id->name);
+ continue;
+ }
+
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
+ BLI_assert(entry != NULL);
+
+ for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != NULL;
+ entry_item = entry_item->next) {
+ if (entry_item->usage_flag &
+ (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ continue;
+ }
+ ID *id_to = *entry_item->id_pointer.to;
+
+ /* Case where this ID pointer was to a linked ID, that now needs to be overridden. */
+ if (ID_IS_LINKED(id_to) && (id_to->tag & LIB_TAG_DOIT) != 0) {
+ id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ CLOG_INFO(&LOG,
+ 3,
+ "ID %s now tagged as needing resync because they use linked %s that now needs "
+ "to be overridden",
+ id->name,
+ id_to->name);
+ break;
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ BKE_main_relations_free(bmain);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* And do the actual resync for all IDs detected as needing it.
+ * NOTE: Since this changes `bmain` (adding **and** removing IDs), we cannot use
+ * `FOREACH_MAIN_ID_BEGIN/END` here, and need special multi-loop processing. */
+ bool do_continue = true;
+ while (do_continue) {
+ ListBase *lb;
+ do_continue = false;
+ FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) {
+ if ((id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0) {
+ continue;
+ }
+ do_continue = true;
+ CLOG_INFO(&LOG, 2, "Resyncing %s...", id->name);
+ const bool success = BKE_lib_override_library_resync(bmain, scene, view_layer, id, false);
+ CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
+ break;
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ if (do_continue) {
+ break;
+ }
+ }
+ FOREACH_MAIN_LISTBASE_END;
+ }
+}
+
+/**
* Advanced 'smart' function to delete library overrides (including their existing override
* hierarchy) and remap their usages to their linked reference IDs.
*
@@ -1372,6 +1565,53 @@ bool BKE_lib_override_library_property_operation_operands_validate(
return true;
}
+/** Check against potential \a bmain. */
+void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
+{
+ if (id->override_library == NULL) {
+ return;
+ }
+ if (id->override_library->reference == NULL) {
+ /* This is a template ID, could be linked or local, not an override. */
+ return;
+ }
+ if (id->override_library->reference == id) {
+ /* Very serious data corruption, cannot do much about it besides removing the reference
+ * (therefore making the id a local override template one only). */
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Data corruption: data-block '%s' is using itself as library override reference",
+ id->name);
+ id->override_library->reference = NULL;
+ return;
+ }
+ if (id->override_library->reference->lib == NULL) {
+ /* Very serious data corruption, cannot do much about it besides removing the reference
+ * (therefore making the id a local override template one only). */
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Data corruption: data-block '%s' is using another local data-block ('%s') as "
+ "library override reference",
+ id->name,
+ id->override_library->reference->name);
+ id->override_library->reference = NULL;
+ return;
+ }
+}
+
+/** Check against potential \a bmain. */
+void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
+{
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (id->override_library != NULL) {
+ BKE_lib_override_library_validate(bmain, id, reports);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+}
+
/**
* Check that status of local data-block is still valid against current reference one.
*
@@ -1557,17 +1797,15 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
created = true;
}
-#ifndef NDEBUG
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
- printf("We did restore some properties of %s from its reference.\n", local->name);
+ CLOG_INFO(&LOG, 2, "We did restore some properties of %s from its reference", local->name);
}
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
- printf("We did generate library override rules for %s\n", local->name);
+ CLOG_INFO(&LOG, 2, "We did generate library override rules for %s", local->name);
}
else {
- printf("No new library override rules for %s\n", local->name);
+ CLOG_INFO(&LOG, 2, "No new library override rules for %s", local->name);
}
-#endif
}
return created;
}
@@ -1880,6 +2118,14 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
FOREACH_MAIN_ID_END;
}
+static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp)
+{
+ BKE_lib_id_swap(bmain, id_local, id_temp);
+ /* We need to keep these tags from temp ID into orig one.
+ * ID swap does not swap most of ID data itself. */
+ id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC);
+}
+
/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
@@ -1943,16 +2189,20 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
RNA_id_pointer_create(local->override_library->storage, rnaptr_storage);
}
- RNA_struct_override_apply(
- bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_library);
+ RNA_struct_override_apply(bmain,
+ &rnaptr_dst,
+ &rnaptr_src,
+ rnaptr_storage,
+ local->override_library,
+ RNA_OVERRIDE_APPLY_FLAG_NOP);
/* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa.
* So when we'll free tmp_id, we'll actually free old, outdated data from local. */
- BKE_lib_id_swap(bmain, local, tmp_id);
+ lib_override_id_swap(bmain, local, tmp_id);
if (local_key != NULL && tmp_key != NULL) {
/* This is some kind of hard-coded 'always enforced override'. */
- BKE_lib_id_swap(bmain, &local_key->id, &tmp_key->id);
+ lib_override_id_swap(bmain, &local_key->id, &tmp_key->id);
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
/* The swap of local and tmp_id inverted those pointers, we need to redefine proper
* relationships. */
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 796bc3dc3d0..e33743eb36b 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -183,8 +183,9 @@ static void library_foreach_ID_link(Main *bmain,
BLI_assert(inherit_data == NULL || data.bmain == inherit_data->bmain);
if (flag & IDWALK_RECURSE) {
- /* For now, recursion implies read-only. */
+ /* For now, recursion implies read-only, and no internal pointers. */
flag |= IDWALK_READONLY;
+ flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS;
data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
BLI_LINKSTACK_INIT(data.ids_todo);
@@ -230,6 +231,7 @@ static void library_foreach_ID_link(Main *bmain,
}
if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY) &&
+ (flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) == 0 &&
(((bmain->relations->flag & MAINIDRELATIONS_INCLUDE_UI) == 0) ==
((data.flag & IDWALK_INCLUDE_UI) == 0))) {
/* Note that this is minor optimization, even in worst cases (like id being an object with
@@ -250,6 +252,11 @@ static void library_foreach_ID_link(Main *bmain,
/* Note: ID.lib pointer is purposefully fully ignored here...
* We may want to add it at some point? */
+ if (flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) {
+ CALLBACK_INVOKE_ID(id->newid, IDWALK_CB_INTERNAL);
+ CALLBACK_INVOKE_ID(id->orig_id, IDWALK_CB_INTERNAL);
+ }
+
if (id->override_library != NULL) {
CALLBACK_INVOKE_ID(id->override_library->reference,
IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
@@ -440,7 +447,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
typedef struct IDUsersIter {
ID *id;
- ListBase *lb_array[MAX_LIBARRAY];
+ ListBase *lb_array[INDEX_ID_MAX];
int lb_idx;
ID *curr_id;
@@ -514,7 +521,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
{
IDUsersIter iter;
- ListBase *lb_array[MAX_LIBARRAY];
+ ListBase *lb_array[INDEX_ID_MAX];
ID *id = idv;
int i = set_listbasepointers(bmain, lb_array);
bool is_defined = false;
@@ -567,7 +574,7 @@ bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
{
IDUsersIter iter;
- ListBase *lb_array[MAX_LIBARRAY];
+ ListBase *lb_array[INDEX_ID_MAX];
ID *id = idv;
int i = set_listbasepointers(bmain, lb_array);
bool is_defined = false;
@@ -805,7 +812,7 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
*/
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
{
- ListBase *lb_array[MAX_LIBARRAY];
+ ListBase *lb_array[INDEX_ID_MAX];
bool do_loop = true;
while (do_loop) {
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 56f7bb0be6f..1f597bbb9a6 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -373,9 +373,12 @@ static void libblock_remap_data(
Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
{
IDRemap id_remap_data;
- const int foreach_id_flags = (remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ?
- IDWALK_NO_INDIRECT_PROXY_DATA_USAGE :
- IDWALK_NOP;
+ const int foreach_id_flags = ((remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ?
+ IDWALK_NO_INDIRECT_PROXY_DATA_USAGE :
+ IDWALK_NOP) |
+ ((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
+ IDWALK_DO_INTERNAL_RUNTIME_POINTERS :
+ IDWALK_NOP);
if (r_id_remap_data == NULL) {
r_id_remap_data = &id_remap_data;
@@ -422,15 +425,17 @@ static void libblock_remap_data(
FOREACH_MAIN_ID_END;
}
- /* XXX We may not want to always 'transfer' fake-user from old to new id...
- * Think for now it's desired behavior though,
- * we can always add an option (flag) to control this later if needed. */
- if (old_id && (old_id->flag & LIB_FAKEUSER)) {
- id_fake_user_clear(old_id);
- id_fake_user_set(new_id);
- }
+ if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) {
+ /* XXX We may not want to always 'transfer' fake-user from old to new id...
+ * Think for now it's desired behavior though,
+ * we can always add an option (flag) to control this later if needed. */
+ if (old_id && (old_id->flag & LIB_FAKEUSER)) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
- id_us_clear_real(old_id);
+ id_us_clear_real(old_id);
+ }
if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
(r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
@@ -479,12 +484,14 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
skipped_direct = id_remap_data.skipped_direct;
skipped_refcounted = id_remap_data.skipped_refcounted;
- /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user
- * count has actually been incremented for that, we have to decrease once more its user count...
- * unless we had to skip some 'user_one' cases. */
- if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) &&
- !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
- id_us_clear_real(old_id);
+ if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) {
+ /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user
+ * count has actually been incremented for that, we have to decrease once more its user
+ * count... unless we had to skip some 'user_one' cases. */
+ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) &&
+ !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
+ id_us_clear_real(old_id);
+ }
}
if (old_id->us - skipped_refcounted < 0) {
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 6f94b3355fa..d1f34ad8ce9 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -53,7 +53,7 @@ Main *BKE_main_new(void)
void BKE_main_free(Main *mainvar)
{
/* also call when reading a file, erase all, etc */
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a;
/* Since we are removing whole main, no need to bother 'properly'
@@ -532,18 +532,17 @@ ListBase *which_libbase(Main *bmain, short type)
}
/**
- * puts into array *lb pointers to all the #ListBase structs in main,
- * and returns the number of them as the function result. This is useful for
- * generic traversal of all the blocks in a Main (by traversing all the
- * lists in turn), without worrying about block types.
+ * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
+ * array, and return the number of those for convenience.
*
- * \note #MAX_LIBARRAY define should match this code */
-int set_listbasepointers(Main *bmain, ListBase **lb)
+ * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
+ * in turn), without worrying about block types.
+ *
+ * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
+ * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
+ */
+int set_listbasepointers(Main *bmain, ListBase *lb[INDEX_ID_MAX])
{
- /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
- * This is important because freeing data decreases user-counts of other data-blocks,
- * if this data is its self freed it can crash. */
-
/* Libraries may be accessed from pretty much any other ID. */
lb[INDEX_ID_LI] = &(bmain->libraries);
@@ -606,5 +605,5 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
lb[INDEX_ID_NULL] = NULL;
- return (MAX_LIBARRAY - 1);
+ return (INDEX_ID_MAX - 1);
}
diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c
index 21f5e9c6fb2..1d362db4432 100644
--- a/source/blender/blenkernel/intern/main_idmap.c
+++ b/source/blender/blenkernel/intern/main_idmap.c
@@ -66,7 +66,7 @@ struct IDNameLib_TypeMap {
* Opaque structure, external API users only see this.
*/
struct IDNameLib_Map {
- struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
+ struct IDNameLib_TypeMap type_maps[INDEX_ID_MAX];
struct GHash *uuid_map;
struct Main *bmain;
struct GSet *valid_id_pointers;
@@ -77,7 +77,7 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id
short id_type)
{
if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
- for (int i = 0; i < MAX_LIBARRAY; i++) {
+ for (int i = 0; i < INDEX_ID_MAX; i++) {
if (id_map->type_maps[i].id_type == id_type) {
return &id_map->type_maps[i];
}
@@ -108,13 +108,13 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
id_map->idmap_types = idmap_types;
int index = 0;
- while (index < MAX_LIBARRAY) {
+ while (index < INDEX_ID_MAX) {
struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
type_map->map = NULL;
type_map->id_type = BKE_idtype_idcode_iter_step(&index);
BLI_assert(type_map->id_type != 0);
}
- BLI_assert(index == MAX_LIBARRAY);
+ BLI_assert(index == INDEX_ID_MAX);
if (idmap_types & MAIN_IDMAP_TYPE_UUID) {
ID *id;
@@ -231,7 +231,7 @@ void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
{
if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
struct IDNameLib_TypeMap *type_map = id_map->type_maps;
- for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
+ for (int i = 0; i < INDEX_ID_MAX; i++, type_map++) {
if (type_map->map) {
BLI_ghash_free(type_map->map, NULL, NULL);
type_map->map = NULL;
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 299b1ff1c71..824f791d400 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -32,6 +32,7 @@
#include "BLI_alloca.h"
#include "BLI_float2.hh"
+#include "BLI_float4x4.hh"
#include "BLI_math.h"
#include "BLI_mesh_boolean.hh"
#include "BLI_mesh_intersect.hh"
@@ -50,12 +51,12 @@ constexpr int estimated_max_facelen = 100; /* Used for initial size of some Vect
* so this is a hack to clean up such matrices.
* Would be better to change the transformation code itself.
*/
-static void clean_obmat(float cleaned[4][4], const float mat[4][4])
+static void clean_obmat(float4x4 &cleaned, const float4x4 &mat)
{
const float fuzz = 1e-6f;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- float f = mat[i][j];
+ float f = mat.values[i][j];
if (fabsf(f) <= fuzz) {
f = 0.0f;
}
@@ -65,17 +66,11 @@ static void clean_obmat(float cleaned[4][4], const float mat[4][4])
else if (fabsf(f + 1.0f) <= fuzz) {
f = -1.0f;
}
- cleaned[i][j] = f;
+ cleaned.values[i][j] = f;
}
}
}
-/* Need to wrap this in a class to use it in an Array. */
-class TransMat {
- public:
- float mat[4][4];
-};
-
/* `MeshesToIMeshInfo` keeps track of information used when combining a number
* of `Mesh`es into a single `IMesh` for doing boolean on.
* Mostly this means keeping track of the index offsets for various mesh elements. */
@@ -97,7 +92,10 @@ class MeshesToIMeshInfo {
Array<Face *> mesh_to_imesh_face;
/* Transformation matrix to transform a coordinate in the corresponding
* Mesh to the local space of the first Mesh. */
- Array<TransMat> to_obj0;
+ Array<float4x4> to_obj0;
+ /* For each input mesh, how to remap the material slot numbers to
+ * the material slots in the first mesh. */
+ Array<const short *> material_remaps;
/* Total number of input mesh vertices. */
int tot_meshes_verts;
/* Total number of input mesh edges. */
@@ -242,7 +240,8 @@ const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
* All allocation of memory for the IMesh comes from `arena`.
*/
static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
- const float (*obmats[])[4][4],
+ Span<const float4x4 *> obmats,
+ Span<const short *> material_remaps,
IMeshArena &arena,
MeshesToIMeshInfo *r_info)
{
@@ -271,7 +270,8 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
r_info->mesh_vert_offset = Array<int>(nmeshes);
r_info->mesh_edge_offset = Array<int>(nmeshes);
r_info->mesh_poly_offset = Array<int>(nmeshes);
- r_info->to_obj0 = Array<TransMat>(nmeshes);
+ r_info->to_obj0 = Array<float4x4>(nmeshes);
+ r_info->material_remaps = Array<const short *>(nmeshes);
int v = 0;
int e = 0;
int f = 0;
@@ -286,15 +286,15 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
* of object 0, we multiply each object's `obmat` by the inverse of
* object 0's `obmat`. Exact Boolean works better if these matrices
* are 'cleaned' -- see the comment for the `clean_obmat` function, above. */
- float obj0_mat[4][4];
- float inv_obj0_mat[4][4];
+ float4x4 obj0_mat;
+ float4x4 inv_obj0_mat;
if (obmats[0] == nullptr) {
- unit_m4(obj0_mat);
- unit_m4(inv_obj0_mat);
+ unit_m4(obj0_mat.values);
+ unit_m4(inv_obj0_mat.values);
}
else {
clean_obmat(obj0_mat, *obmats[0]);
- invert_m4_m4(inv_obj0_mat, obj0_mat);
+ invert_m4_m4(inv_obj0_mat.values, obj0_mat.values);
}
/* For each input `Mesh`, make `Vert`s and `Face`s for the corresponding
@@ -303,13 +303,14 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
* When making `Face`s, we also put in the original indices for `MEdge`s that
* make up the `MPoly`s using the same scheme. */
for (int mi : meshes.index_range()) {
- float objn_to_obj0_mat[4][4];
+ float4x4 objn_to_obj0_mat;
const Mesh *me = meshes[mi];
if (mi == 0) {
r_info->mesh_vert_offset[mi] = 0;
r_info->mesh_edge_offset[mi] = 0;
r_info->mesh_poly_offset[mi] = 0;
- unit_m4(r_info->to_obj0[0].mat);
+ unit_m4(r_info->to_obj0[0].values);
+ r_info->material_remaps[0] = nullptr;
}
else {
r_info->mesh_vert_offset[mi] = v;
@@ -317,23 +318,28 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
r_info->mesh_poly_offset[mi] = f;
/* Get matrix that transforms a coordinate in objects[mi]'s local space
* to object[0]'s local space.*/
- float objn_mat[4][4];
+ float4x4 objn_mat;
if (obmats[mi] == nullptr) {
- unit_m4(objn_mat);
+ unit_m4(objn_mat.values);
}
else {
clean_obmat(objn_mat, *obmats[mi]);
}
- mul_m4_m4m4(objn_to_obj0_mat, inv_obj0_mat, objn_mat);
- copy_m4_m4(r_info->to_obj0[mi].mat, objn_to_obj0_mat);
+ objn_to_obj0_mat = inv_obj0_mat * objn_mat;
+ r_info->to_obj0[mi] = objn_to_obj0_mat;
+ if (mi < material_remaps.size()) {
+ r_info->material_remaps[mi] = material_remaps[mi];
+ }
+ else {
+ r_info->material_remaps[mi] = nullptr;
+ }
}
for (int vi = 0; vi < me->totvert; ++vi) {
- float co[3];
- copy_v3_v3(co, me->mvert[vi].co);
+ float3 co = me->mvert[vi].co;
if (mi > 0) {
- mul_m4_v3(objn_to_obj0_mat, co);
+ co = objn_to_obj0_mat * co;
}
- r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(mpq3(co[0], co[1], co[2]), v);
+ r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(mpq3(co.x, co.y, co.z), v);
++v;
}
for (const MPoly &poly : Span(me->mpoly, me->totpoly)) {
@@ -396,12 +402,21 @@ static void copy_poly_attributes(Mesh *dest_mesh,
const MPoly *orig_mp,
const Mesh *orig_me,
int mp_index,
- int index_in_orig_me)
+ int index_in_orig_me,
+ const short *material_remap)
{
mp->mat_nr = orig_mp->mat_nr;
if (mp->mat_nr >= dest_mesh->totcol) {
mp->mat_nr = 0;
}
+ else {
+ if (material_remap) {
+ short mat_nr = material_remap[orig_mp->mat_nr];
+ if (mat_nr >= 0 && mat_nr < dest_mesh->totcol) {
+ mp->mat_nr = mat_nr;
+ }
+ }
+ }
mp->flag = orig_mp->flag;
CustomData *target_cd = &dest_mesh->pdata;
const CustomData *source_cd = &orig_me->pdata;
@@ -534,7 +549,7 @@ static int fill_orig_loops(const Face *f,
static void get_poly2d_cos(const Mesh *me,
const MPoly *mp,
float (*cos_2d)[2],
- const TransMat &trans_mat,
+ const float4x4 &trans_mat,
float r_axis_mat[3][3])
{
int n = mp->totloop;
@@ -546,9 +561,8 @@ static void get_poly2d_cos(const Mesh *me,
MLoop *ml = &me->mloop[mp->loopstart];
const MVert *mverts = me->mvert;
for (int i = 0; i < n; ++i) {
- float co[3];
- copy_v3_v3(co, mverts[ml->v].co);
- mul_m4_v3(trans_mat.mat, co);
+ float3 co = mverts[ml->v].co;
+ co = trans_mat * co;
mul_v2_m3v3(cos_2d[i], r_axis_mat, co);
++ml;
}
@@ -618,6 +632,9 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
* A non bmesh version could have the benefit of not copying data into src_blocks_ofs -
* using the contiguous data instead. TODO: add to the custom data API. */
int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name);
+ if (!CustomData_layer_has_interp(source_cd, source_layer_i)) {
+ continue;
+ }
int source_layer_type_index = source_layer_i - source_cd->typemap[ty];
BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0);
for (int j = 0; j < orig_mp->totloop; ++j) {
@@ -725,7 +742,9 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
++l;
++cur_loop_index;
}
- copy_poly_attributes(result, mp, orig_mp, orig_me, fi, index_in_orig_me);
+
+ copy_poly_attributes(
+ result, mp, orig_mp, orig_me, fi, index_in_orig_me, mim.material_remaps[orig_me_index]);
copy_or_interp_loop_attributes(result, f, mp, orig_mp, orig_me, orig_me_index, mim);
}
@@ -763,23 +782,25 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
* Do Exact Boolean directly, without a round trip through #BMesh.
* The Mesh operands are in `meshes`, with corresponding transforms in in `obmats`.
*/
-static Mesh *direct_mesh_boolean(const Mesh **meshes,
- const float (*obmats[])[4][4],
- const int meshes_len,
+static Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
+ Span<const float4x4 *> obmats,
+ Span<const short *> material_remaps,
const bool use_self,
+ const bool hole_tolerant,
const BoolOpType boolean_mode)
{
const int dbg_level = 0;
+ BLI_assert(meshes.size() == obmats.size());
+ const int meshes_len = meshes.size();
if (meshes_len <= 0) {
return nullptr;
}
if (dbg_level > 0) {
std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes_len << "\n";
}
- Span<const Mesh *> mesh_span(meshes, meshes_len);
MeshesToIMeshInfo mim;
IMeshArena arena;
- IMesh m_in = meshes_to_imesh(mesh_span, obmats, arena, &mim);
+ IMesh m_in = meshes_to_imesh(meshes, obmats, material_remaps, arena, &mim);
std::function<int(int)> shape_fn = [&mim](int f) {
for (int mi = 0; mi < mim.mesh_poly_offset.size() - 1; ++mi) {
if (f < mim.mesh_poly_offset[mi + 1]) {
@@ -788,7 +809,8 @@ static Mesh *direct_mesh_boolean(const Mesh **meshes,
}
return static_cast<int>(mim.mesh_poly_offset.size()) - 1;
};
- IMesh m_out = boolean_mesh(m_in, boolean_mode, meshes_len, shape_fn, use_self, nullptr, &arena);
+ IMesh m_out = boolean_mesh(
+ m_in, boolean_mode, meshes_len, shape_fn, use_self, hole_tolerant, nullptr, &arena);
if (dbg_level > 1) {
std::cout << m_out;
write_obj_mesh(m_out, "m_out");
@@ -806,27 +828,36 @@ extern "C" {
/* Do a mesh boolean directly on meshes (without going back and forth to BMesh).
* The \a meshes argument is an array of \a meshes_len of Mesh pointers.
* The \a obmats argument is an array of \a meshes_len of pointers to the obmat
+ * The \a material_remaps is an array of pointers to arrays of maps from material
+ * slot numbers in the corresponding mesh to the material slot in the first mesh.
+ * It is OK for material_remaps or any of its constituent arrays to be NULL.
* matrices that transform local coordinates to global ones. It is allowed
* for the pointers to be nullptr, meaning the transformation is the identity. */
Mesh *BKE_mesh_boolean(const Mesh **meshes,
const float (*obmats[])[4][4],
+ const short **material_remaps,
const int meshes_len,
const bool use_self,
+ const bool hole_tolerant,
const int boolean_mode)
{
+ const blender::float4x4 **transforms = (const blender::float4x4 **)obmats;
return blender::meshintersect::direct_mesh_boolean(
- meshes,
- obmats,
- meshes_len,
+ blender::Span(meshes, meshes_len),
+ blender::Span(transforms, meshes_len),
+ blender::Span(material_remaps, material_remaps ? meshes_len : 0),
use_self,
+ hole_tolerant,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
#else
Mesh *BKE_mesh_boolean(const Mesh **UNUSED(meshes),
const float (*obmats[])[4][4],
+ const short **UNUSED(material_remaps),
const int UNUSED(meshes_len),
const bool UNUSED(use_self),
+ const bool UNUSED(hole_tolerant),
const int UNUSED(boolean_mode))
{
UNUSED_VARS(obmats);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 55cb0d5cce4..5041f914ef9 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -107,6 +107,9 @@ static void node_free_node(bNodeTree *ntree, bNode *node);
static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
bNodeSocket *sock,
const bool do_id_user);
+static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree,
+ struct bNode *node,
+ const bool mute);
static void ntree_init_data(ID *id)
{
@@ -538,20 +541,14 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
- else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
+ else if ((ntree->type == NTREE_COMPOSIT) &&
+ (ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY))) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
- /* Update the matte_id so the files can be opened in versions that don't
- * use `CryptomatteEntry`. */
- MEM_SAFE_FREE(nc->matte_id);
- nc->matte_id = BKE_cryptomatte_entries_to_matte_id(nc);
- if (nc->matte_id) {
- BLO_write_string(writer, nc->matte_id);
- }
+ BLO_write_string(writer, nc->matte_id);
LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) {
BLO_write_struct(writer, CryptomatteEntry, entry);
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
- MEM_SAFE_FREE(nc->matte_id);
}
else if (node->type == FN_NODE_INPUT_STRING) {
NodeInputString *storage = (NodeInputString *)node->storage;
@@ -710,10 +707,12 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
iuser->scene = nullptr;
break;
}
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
case CMP_NODE_CRYPTOMATTE: {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_read_data_address(reader, &nc->matte_id);
BLO_read_list(reader, &nc->entries);
+ BLI_listbase_clear(&nc->runtime.layers);
break;
}
case TEX_NODE_IMAGE: {
@@ -910,7 +909,8 @@ void ntreeBlendReadExpand(BlendExpander *expander, bNodeTree *ntree)
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && node->type != CMP_NODE_R_LAYERS) {
+ if (node->id && !(node->type == CMP_NODE_R_LAYERS) &&
+ !(node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) {
BLO_expand(expander, node->id);
}
@@ -1575,6 +1575,8 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketFloatAngle";
case PROP_TIME:
return "NodeSocketFloatTime";
+ case PROP_DISTANCE:
+ return "NodeSocketFloatDistance";
case PROP_NONE:
default:
return "NodeSocketFloat";
@@ -1644,6 +1646,8 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceFloatAngle";
case PROP_TIME:
return "NodeSocketInterfaceFloatTime";
+ case PROP_DISTANCE:
+ return "NodeSocketInterfaceFloatDistance";
case PROP_NONE:
default:
return "NodeSocketInterfaceFloat";
@@ -2214,6 +2218,106 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
}
}
+/* Check if all output links are muted or not. */
+static bool nodeMuteFromSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock)
+{
+ int tot = 0;
+ int muted = 0;
+ LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sock) {
+ tot++;
+ if (link->flag & NODE_LINK_MUTED) {
+ muted++;
+ }
+ }
+ }
+ return tot == muted;
+}
+
+static void nodeMuteLink(bNodeLink *link)
+{
+ link->flag |= NODE_LINK_MUTED;
+ link->flag |= NODE_LINK_TEST;
+ if (!(link->tosock->flag & SOCK_MULTI_INPUT)) {
+ link->tosock->flag &= ~SOCK_IN_USE;
+ }
+}
+
+static void nodeUnMuteLink(bNodeLink *link)
+{
+ link->flag &= ~NODE_LINK_MUTED;
+ link->flag |= NODE_LINK_TEST;
+ link->tosock->flag |= SOCK_IN_USE;
+}
+
+/* Upstream muting. Always happens when unmuting but checks when muting. O(n^2) algorithm.*/
+static void nodeMuteRerouteInputLinks(bNodeTree *ntree, bNode *node, const bool mute)
+{
+ if (node->type != NODE_REROUTE) {
+ return;
+ }
+ if (!mute || nodeMuteFromSocketLinks(ntree, (bNodeSocket *)node->outputs.first)) {
+ bNodeSocket *sock = (bNodeSocket *)node->inputs.first;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (!(link->flag & NODE_LINK_VALID) || (link->tosock != sock)) {
+ continue;
+ }
+ if (mute) {
+ nodeMuteLink(link);
+ }
+ else {
+ nodeUnMuteLink(link);
+ }
+ nodeMuteRerouteInputLinks(ntree, link->fromnode, mute);
+ }
+ }
+}
+
+/* Downstream muting propagates when reaching reroute nodes. O(n^2) algorithm.*/
+static void nodeMuteRerouteOutputLinks(bNodeTree *ntree, bNode *node, const bool mute)
+{
+ if (node->type != NODE_REROUTE) {
+ return;
+ }
+ bNodeSocket *sock;
+ sock = (bNodeSocket *)node->outputs.first;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (!(link->flag & NODE_LINK_VALID) || (link->fromsock != sock)) {
+ continue;
+ }
+ if (mute) {
+ nodeMuteLink(link);
+ }
+ else {
+ nodeUnMuteLink(link);
+ }
+ nodeMuteRerouteOutputLinks(ntree, link->tonode, mute);
+ }
+}
+
+void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link)
+{
+ if (link->tosock) {
+ bool mute = !(link->flag & NODE_LINK_MUTED);
+ if (mute) {
+ nodeMuteLink(link);
+ }
+ else {
+ nodeUnMuteLink(link);
+ }
+ if (link->tonode->type == NODE_REROUTE) {
+ nodeMuteRerouteOutputLinks(ntree, link->tonode, mute);
+ }
+ if (link->fromnode->type == NODE_REROUTE) {
+ nodeMuteRerouteInputLinks(ntree, link->fromnode, mute);
+ }
+ }
+
+ if (ntree) {
+ ntree->update |= NTREE_UPDATE_LINKS;
+ }
+}
+
void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
@@ -2256,6 +2360,10 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
link->flag &= ~NODE_LINK_VALID;
}
+ if (fromlink->flag & NODE_LINK_MUTED) {
+ link->flag |= NODE_LINK_MUTED;
+ }
+
ntree->update |= NTREE_UPDATE_LINKS;
}
else {
@@ -4013,7 +4121,9 @@ void ntreeTagUsedSockets(bNodeTree *ntree)
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
link->fromsock->flag |= SOCK_IN_USE;
- link->tosock->flag |= SOCK_IN_USE;
+ if (!(link->flag & NODE_LINK_MUTED)) {
+ link->tosock->flag |= SOCK_IN_USE;
+ }
}
}
@@ -4482,18 +4592,18 @@ void node_type_group_update(struct bNodeType *ntype,
}
void node_type_exec(struct bNodeType *ntype,
- NodeInitExecFunction initexecfunc,
- NodeFreeExecFunction freeexecfunc,
- NodeExecFunction execfunc)
+ NodeInitExecFunction init_exec_fn,
+ NodeFreeExecFunction free_exec_fn,
+ NodeExecFunction exec_fn)
{
- ntype->initexecfunc = initexecfunc;
- ntype->freeexecfunc = freeexecfunc;
- ntype->execfunc = execfunc;
+ ntype->init_exec_fn = init_exec_fn;
+ ntype->free_exec_fn = free_exec_fn;
+ ntype->exec_fn = exec_fn;
}
-void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc)
+void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn)
{
- ntype->gpufunc = gpufunc;
+ ntype->gpu_fn = gpu_fn;
}
void node_type_internal_links(bNodeType *ntype,
@@ -4610,6 +4720,7 @@ static void registerCompositNodes()
register_node_type_cmp_keyingscreen();
register_node_type_cmp_keying();
register_node_type_cmp_cryptomatte();
+ register_node_type_cmp_cryptomatte_legacy();
register_node_type_cmp_translate();
register_node_type_cmp_rotate();
@@ -4795,6 +4906,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_color_ramp();
register_node_type_geo_attribute_combine_xyz();
register_node_type_geo_attribute_compare();
+ register_node_type_geo_attribute_convert();
register_node_type_geo_attribute_fill();
register_node_type_geo_attribute_math();
register_node_type_geo_attribute_mix();
@@ -4802,11 +4914,20 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_randomize();
register_node_type_geo_attribute_separate_xyz();
register_node_type_geo_attribute_vector_math();
+ register_node_type_geo_attribute_remove();
register_node_type_geo_boolean();
register_node_type_geo_collection_info();
register_node_type_geo_edge_split();
register_node_type_geo_is_viewport();
register_node_type_geo_join_geometry();
+ register_node_type_geo_mesh_primitive_circle();
+ register_node_type_geo_mesh_primitive_cone();
+ register_node_type_geo_mesh_primitive_cube();
+ register_node_type_geo_mesh_primitive_cylinder();
+ register_node_type_geo_mesh_primitive_ico_sphere();
+ register_node_type_geo_mesh_primitive_line();
+ register_node_type_geo_mesh_primitive_plane();
+ register_node_type_geo_mesh_primitive_uv_sphere();
register_node_type_geo_object_info();
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
@@ -4816,8 +4937,8 @@ static void registerGeometryNodes()
register_node_type_geo_point_translate();
register_node_type_geo_points_to_volume();
register_node_type_geo_sample_texture();
+ register_node_type_geo_subdivide();
register_node_type_geo_subdivision_surface();
- register_node_type_geo_subdivision_surface_simple();
register_node_type_geo_transform();
register_node_type_geo_triangulate();
register_node_type_geo_volume_to_mesh();
diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc
index 6e0253eca31..f2a152ac00d 100644
--- a/source/blender/blenkernel/intern/node_ui_storage.cc
+++ b/source/blender/blenkernel/intern/node_ui_storage.cc
@@ -62,8 +62,12 @@ const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C
}
const Object *active_object = CTX_data_active_object(C);
+ if (active_object == nullptr) {
+ return nullptr;
+ }
+
const ModifierData *active_modifier = BKE_object_active_modifier(active_object);
- if (active_object == nullptr || active_modifier == nullptr) {
+ if (active_modifier == nullptr) {
return nullptr;
}
@@ -154,8 +158,11 @@ void BKE_nodetree_error_message_add(bNodeTree &ntree,
void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
const NodeTreeEvaluationContext &context,
const bNode &node,
- const StringRef attribute_name)
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
{
NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ntree, context, node);
- node_ui_storage.attribute_name_hints.add_as(attribute_name);
+ node_ui_storage.attribute_hints.add_as(attribute_name,
+ AvailableAttributeInfo{domain, data_type});
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 69442b7646c..1e6a099040f 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -176,12 +176,14 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
CustomData_MeshMasks cddata_masks = scene->customdata_mask;
CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
- if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
- /* Make sure Freestyle edge/face marks appear in DM for render (see T40315). */
+ /* Make sure Freestyle edge/face marks appear in DM for render (see T40315). Due to Line Art
+ * impementation, edge marks should also be shown in viewport. */
#ifdef WITH_FREESTYLE
- cddata_masks.emask |= CD_MASK_FREESTYLE_EDGE;
- cddata_masks.pmask |= CD_MASK_FREESTYLE_FACE;
+ cddata_masks.emask |= CD_MASK_FREESTYLE_EDGE;
+ cddata_masks.pmask |= CD_MASK_FREESTYLE_FACE;
+ cddata_masks.vmask |= CD_MASK_MDEFORMVERT;
#endif
+ if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
/* Always compute UVs, vertex colors as orcos for render. */
cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
cddata_masks.vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 05873d20f7f..b9497d389e7 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -101,7 +101,7 @@ static unsigned int tse_hash(const void *ptr)
unsigned int u_int;
} hash;
- BLI_assert(tse->type || !tse->nr);
+ BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr);
hash.h_pair[0] = tse->type;
hash.h_pair[1] = tse->nr;
@@ -193,7 +193,7 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short
{
TreeStoreElem tse_template;
tse_template.type = type;
- tse_template.nr = type ? nr : 0; /* we're picky! :) */
+ tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */
tse_template.id = id;
BLI_assert(th);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 08c5beedbf3..2e81b61ad8c 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1760,7 +1760,7 @@ void BKE_sculpt_update_object_before_eval(Object *ob)
SculptSession *ss = ob->sculpt;
if (ss && ss->building_vp_handle == false) {
- if (!ss->cache && !ss->filter_cache) {
+ if (!ss->cache && !ss->filter_cache && !ss->expand_cache) {
/* We free pbvh on changes, except in the middle of drawing a stroke
* since it can't deal with changing PVBH node organization, we hope
* topology does not change in the meantime .. weak. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index acda59ce96c..e50b321900a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3925,7 +3925,7 @@ static ModifierData *object_add_or_copy_particle_system(
}
if (name == NULL) {
- name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSettings");
+ name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSystem");
}
psys = ob->particlesystem.first;
@@ -3943,7 +3943,7 @@ static ModifierData *object_add_or_copy_particle_system(
id_us_plus(&psys->part->id);
}
else {
- psys->part = BKE_particlesettings_add(bmain, psys->name);
+ psys->part = BKE_particlesettings_add(bmain, DATA_("ParticleSettings"));
}
md = BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(md->name, psys->name, sizeof(md->name));
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index c3cc9136057..ad617b4198b 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -338,18 +338,18 @@ static void hammersley_create(float *out, int n, int seed, float amount)
{
RNG *rng;
- double offs[2], t;
+ double ofs[2], t;
rng = BLI_rng_new(31415926 + n + seed);
- offs[0] = BLI_rng_get_double(rng) + (double)amount;
- offs[1] = BLI_rng_get_double(rng) + (double)amount;
+ ofs[0] = BLI_rng_get_double(rng) + (double)amount;
+ ofs[1] = BLI_rng_get_double(rng) + (double)amount;
BLI_rng_free(rng);
for (int k = 0; k < n; k++) {
BLI_hammersley_1d(k, &t);
- out[2 * k + 0] = fmod((double)k / (double)n + offs[0], 1.0);
- out[2 * k + 1] = fmod(t + offs[1], 1.0);
+ out[2 * k + 0] = fmod((double)k / (double)n + ofs[0], 1.0);
+ out[2 * k + 1] = fmod(t + ofs[1], 1.0);
}
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 8a98780d918..77dde3a921a 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -137,8 +137,7 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node)
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_ALL) {
BB_expand(&vb, vd.co);
}
BKE_pbvh_vertex_iter_end;
@@ -1143,8 +1142,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_ALL) {
if (vd.mask && *vd.mask < 1.0f) {
has_unmasked = true;
}
@@ -1191,8 +1189,7 @@ static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
BKE_pbvh_node_fully_hidden_set(node, true);
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_ALL) {
if (vd.visible) {
BKE_pbvh_node_fully_hidden_set(node, false);
return;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3633dff8690..de3e1023b08 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1377,9 +1377,10 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
/* patch for missing scene IDs, can't be in do-versions */
static void composite_patch(bNodeTree *ntree, Scene *scene)
{
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == NULL && node->type == CMP_NODE_R_LAYERS) {
+ if (node->id == NULL &&
+ ((node->type == CMP_NODE_R_LAYERS) ||
+ (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER))) {
node->id = &scene->id;
}
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 8b911143668..1766ac5b85f 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -224,6 +224,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
break;
}
+ case SPACE_SPREADSHEET: {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, sspreadsheet->pinned_id, IDWALK_CB_NOP);
+ break;
+ }
default:
break;
}
@@ -1217,7 +1223,7 @@ static void write_panel_list(BlendWriter *writer, ListBase *lb)
}
}
-static void write_area_regions(BlendWriter *writer, ScrArea *area)
+static void write_area(BlendWriter *writer, ScrArea *area)
{
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
write_region(writer, region, area->spacetype);
@@ -1342,6 +1348,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area)
else if (sl->spacetype == SPACE_INFO) {
BLO_write_struct(writer, SpaceInfo, sl);
}
+ else if (sl->spacetype == SPACE_SPREADSHEET) {
+ BLO_write_struct(writer, SpaceSpreadsheet, sl);
+ }
}
}
@@ -1356,7 +1365,7 @@ void BKE_screen_area_map_blend_write(BlendWriter *writer, ScrAreaMap *area_map)
BLO_write_struct(writer, ScrGlobalAreaData, area->global);
- write_area_regions(writer, area);
+ write_area(writer, area);
area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */
}
@@ -1681,6 +1690,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
sfile->op = NULL;
sfile->previews_timer = NULL;
sfile->tags = 0;
+ sfile->runtime = NULL;
BLO_read_data_address(reader, &sfile->params);
BLO_read_data_address(reader, &sfile->asset_params);
}
@@ -1691,6 +1701,11 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
sclip->scopes.track_preview = NULL;
sclip->scopes.ok = 0;
}
+ else if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+
+ sspreadsheet->runtime = NULL;
+ }
}
BLI_listbase_clear(&area->actionzones);
@@ -1904,6 +1919,11 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr
BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask);
break;
}
+ case SPACE_SPREADSHEET: {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ BLO_read_id_address(reader, parent_id->lib, &sspreadsheet->pinned_id);
+ break;
+ }
default:
break;
}
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 6b46804c251..216563b860d 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -54,7 +54,6 @@
#include "BLI_map.hh"
#include "BLT_translation.h"
-#include "FN_attributes_ref.hh"
#include "FN_multi_function_network_evaluation.hh"
#include "FN_multi_function_network_optimization.hh"
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index a33fedb3ea6..6dd1f66f6b5 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -413,7 +413,7 @@ void BKE_sound_init(Main *bmain)
}
if (!(sound_device = AUD_init(device_name, specs, buffersize, "Blender"))) {
- sound_device = AUD_init("Null", specs, buffersize, "Blender");
+ sound_device = AUD_init("None", specs, buffersize, "Blender");
}
BKE_sound_init_main(bmain);
@@ -994,7 +994,7 @@ int BKE_sound_scene_playing(Scene *scene)
return -1;
}
- /* In case of a "Null" audio device, we have no playback information. */
+ /* In case of a "None" audio device, we have no playback information. */
if (AUD_Device_getRate(sound_device) == AUD_RATE_INVALID) {
return -1;
}
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 5bffcd4d9e7..4cc2d101b02 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -514,7 +514,7 @@ static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
ImBuf *ibuf = sli->ibuf;
float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
- float(*offset4)[4] = (float(*)[4])ibuf->rect_float;
+ const float(*offset4)[4] = (const float(*)[4])ibuf->rect_float;
float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
copy_v3_v3(*offset3, *offset4);
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index d5e878a9a75..f107fc4d6bc 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -386,7 +386,8 @@ static void autotrack_context_init_tracks_for_clip(AutoTrackContext *context, in
autotrack_track->track = track;
autotrack_track->is_trackable = autotrack_is_track_trackable(context, autotrack_track);
- tracking_configure_tracker(track, NULL, &autotrack_track->track_region_options);
+ tracking_configure_tracker(
+ track, NULL, context->is_backwards, &autotrack_track->track_region_options);
}
}
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index 7e37e438e24..ef36acdc3d5 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -183,8 +183,13 @@ static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip,
/* Fill in libmv tracker options structure with settings need to be used to perform track. */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
+ const bool is_backwards,
libmv_TrackRegionOptions *options)
{
+ options->direction = is_backwards ? LIBMV_TRACK_REGION_BACKWARD : LIBMV_TRACK_REGION_FORWARD;
+
+ /* TODO(sergey): Use explicit conversion, so that options are decoupled between the Libmv library
+ * and enumerator values in DNA. */
options->motion_model = track->motion_model;
options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
@@ -218,6 +223,7 @@ static bool configure_and_run_tracker(ImBuf *destination_ibuf,
int reference_search_area_width,
int reference_search_area_height,
float *mask,
+ const bool is_backward,
double dst_pixel_x[5],
double dst_pixel_y[5])
{
@@ -246,7 +252,7 @@ static bool configure_and_run_tracker(ImBuf *destination_ibuf,
destination_ibuf, track, marker, &new_search_area_width, &new_search_area_height);
/* configure the tracker */
- tracking_configure_tracker(track, mask, &options);
+ tracking_configure_tracker(track, mask, is_backward, &options);
/* Convert the marker corners and center into pixel coordinates in the
* search/destination images. */
@@ -372,6 +378,7 @@ void BKE_tracking_refine_marker(MovieClip *clip,
search_area_width,
search_area_height,
mask,
+ backwards,
dst_pixel_x,
dst_pixel_y);
diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h
index 35c5221efa3..8de6ec93a7c 100644
--- a/source/blender/blenkernel/tracking_private.h
+++ b/source/blender/blenkernel/tracking_private.h
@@ -111,6 +111,7 @@ struct libmv_TrackRegionOptions;
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
+ bool is_backwards,
struct libmv_TrackRegionOptions *options);
struct MovieTrackingMarker *tracking_get_keyframed_marker(struct MovieTrackingTrack *track,
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index bd37d22023b..2847bc960ad 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -89,6 +89,14 @@ bool _bli_array_iter_span(const void *arr,
bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
+bool _bli_array_iter_spiral_square(const void *arr_v,
+ const int arr_shape[2],
+ const size_t elem_size,
+ const int center[2],
+ bool (*test_fn)(const void *arr_item, void *user_data),
+ void *user_data);
+#define BLI_array_iter_spiral_square(arr, arr_shape, center, test_fn, user_data) \
+ _bli_array_iter_spiral_square(arr, arr_shape, sizeof(*(arr)), center, test_fn, user_data)
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
index 84dd0e358a2..cf6e00ba938 100644
--- a/source/blender/blenlib/BLI_float2.hh
+++ b/source/blender/blenlib/BLI_float2.hh
@@ -65,6 +65,11 @@ struct float2 {
return len_squared_v2(*this);
}
+ bool is_zero() const
+ {
+ return this->x == 0.0f && this->y == 0.0f;
+ }
+
float2 &operator+=(const float2 &other)
{
x += other.x;
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
index 9a8870963bf..7e49cc89b52 100644
--- a/source/blender/blenlib/BLI_float3.hh
+++ b/source/blender/blenlib/BLI_float3.hh
@@ -174,6 +174,11 @@ struct float3 {
return len_squared_v3(*this);
}
+ bool is_zero() const
+ {
+ return this->x == 0.0f && this->y == 0.0f && this->z == 0.0f;
+ }
+
void reflect(const float3 &normal)
{
*this = this->reflected(normal);
diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index 2e3212cc83b..39695b110b1 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -88,11 +88,18 @@ namespace blender {
* If there is no other specialization of #DefaultHash for a given type, try to call `hash()` on
* the value. If there is no such method, this will result in a compiler error. Usually that means
* that you have to implement a hash function using one of three strategies listed above.
+ *
+ * In the case of an enum type, the default hash is just to cast the enum value to an integer.
*/
template<typename T> struct DefaultHash {
uint64_t operator()(const T &value) const
{
- return value.hash();
+ if constexpr (std::is_enum_v<T>) {
+ return (uint64_t)value;
+ }
+ else {
+ return value.hash();
+ }
}
};
diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh
index a616ec5cf28..47705b1d40b 100644
--- a/source/blender/blenlib/BLI_linear_allocator.hh
+++ b/source/blender/blenlib/BLI_linear_allocator.hh
@@ -38,18 +38,20 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
uintptr_t current_begin_;
uintptr_t current_end_;
- int64_t next_min_alloc_size_;
#ifdef DEBUG
int64_t debug_allocated_amount_ = 0;
#endif
+ /* Buffers larger than that are not packed together with smaller allocations to avoid wasting
+ * memory. */
+ constexpr static inline int64_t large_buffer_threshold = 4096;
+
public:
LinearAllocator()
{
current_begin_ = 0;
current_end_ = 0;
- next_min_alloc_size_ = 64;
}
~LinearAllocator()
@@ -71,23 +73,23 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
BLI_assert(alignment >= 1);
BLI_assert(is_power_of_2_i(alignment));
-#ifdef DEBUG
- debug_allocated_amount_ += size;
-#endif
-
const uintptr_t alignment_mask = alignment - 1;
const uintptr_t potential_allocation_begin = (current_begin_ + alignment_mask) &
~alignment_mask;
const uintptr_t potential_allocation_end = potential_allocation_begin + size;
if (potential_allocation_end <= current_end_) {
+#ifdef DEBUG
+ debug_allocated_amount_ += size;
+#endif
current_begin_ = potential_allocation_end;
return reinterpret_cast<void *>(potential_allocation_begin);
}
- else {
- this->allocate_new_buffer(size + alignment);
+ if (size <= large_buffer_threshold) {
+ this->allocate_new_buffer(size + alignment, alignment);
return this->allocate(size, alignment);
}
+ return this->allocator_large_buffer(size, alignment);
};
/**
@@ -116,14 +118,14 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
*
* Arguments passed to this method will be forwarded to the constructor of T.
*
- * You must not call `delete` on the returned pointer.
- * Instead, the destruct has to be called explicitly.
+ * You must not call `delete` on the returned value.
+ * Instead, only the destructor has to be called.
*/
- template<typename T, typename... Args> T *construct(Args &&... args)
+ template<typename T, typename... Args> destruct_ptr<T> construct(Args &&... args)
{
void *buffer = this->allocate(sizeof(T), alignof(T));
T *value = new (buffer) T(std::forward<Args>(args)...);
- return value;
+ return destruct_ptr<T>(value);
}
/**
@@ -195,7 +197,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
}
private:
- void allocate_new_buffer(int64_t min_allocation_size)
+ void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment)
{
for (int64_t i : unused_borrowed_buffers_.index_range()) {
Span<char> buffer = unused_borrowed_buffers_[i];
@@ -207,15 +209,29 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
}
}
- const int64_t size_in_bytes = power_of_2_min_u(
- std::max(min_allocation_size, next_min_alloc_size_));
- next_min_alloc_size_ = size_in_bytes * 2;
+ /* Possibly allocate more bytes than necessary for the current allocation. This way more small
+ * allocations can be packed together. Large buffers are allocated exactly to avoid wasting too
+ * much memory. */
+ int64_t size_in_bytes = min_allocation_size;
+ if (size_in_bytes <= large_buffer_threshold) {
+ /* Gradually grow buffer size with each allocation, up to a maximum. */
+ const int grow_size = 1 << std::min<int>(owned_buffers_.size() + 6, 20);
+ size_in_bytes = std::min(large_buffer_threshold,
+ std::max<int64_t>(size_in_bytes, grow_size));
+ }
- void *buffer = allocator_.allocate(size_in_bytes, 8, AT);
+ void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__);
owned_buffers_.append(buffer);
current_begin_ = (uintptr_t)buffer;
current_end_ = current_begin_ + size_in_bytes;
}
+
+ void *allocator_large_buffer(const int64_t size, const int64_t alignment)
+ {
+ void *buffer = allocator_.allocate(size, alignment, __func__);
+ owned_buffers_.append(buffer);
+ return buffer;
+ }
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index c862290b262..028ca31a059 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -117,6 +117,9 @@ MINLINE float sasqrt(float fac);
MINLINE float interpf(float a, float b, float t);
MINLINE double interpd(double a, double b, double t);
+MINLINE float ratiof(float min, float max, float pos);
+MINLINE double ratiod(double min, double max, double pos);
+
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
* operation. */
MINLINE int square_s(short a);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index eac7f25f11a..6324963f06a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -331,6 +331,7 @@ void rescale_m4(float mat[4][4], const float scale[3]);
void transform_pivot_set_m3(float mat[3][3], const float pivot[2]);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
+void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]);
void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]);
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index b3b6855089e..bdbbda9f0c7 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -28,6 +28,7 @@
#include <type_traits>
#include "BLI_utildefines.h"
+#include "MEM_guardedalloc.h"
namespace blender {
@@ -402,6 +403,50 @@ template<typename T, int64_t Size = 1> class TypedBuffer {
}
};
+/* A dynamic stack buffer can be used instead of #alloca when wants to allocate a dynamic amount of
+ * memory on the stack. Using this class has some advantages:
+ * - It falls back to heap allocation, when the size is too large.
+ * - It can be used in loops safely.
+ * - If the buffer is heap allocated, it is free automatically in the destructor.
+ */
+template<size_t ReservedSize = 64, size_t ReservedAlignment = 64>
+class alignas(ReservedAlignment) DynamicStackBuffer {
+ private:
+ /* Don't create an empty array. This causes problems with some compilers. */
+ char reserved_buffer_[(ReservedSize > 0) ? ReservedSize : 1];
+ void *buffer_;
+
+ public:
+ DynamicStackBuffer(const int64_t size, const int64_t alignment)
+ {
+ BLI_assert(size >= 0);
+ BLI_assert(alignment >= 0);
+ if (size <= ReservedSize && alignment <= ReservedAlignment) {
+ buffer_ = reserved_buffer_;
+ }
+ else {
+ buffer_ = MEM_mallocN_aligned(size, alignment, __func__);
+ }
+ }
+ ~DynamicStackBuffer()
+ {
+ if (buffer_ != reserved_buffer_) {
+ MEM_freeN(buffer_);
+ }
+ }
+
+ /* Don't allow any copying or moving of this type. */
+ DynamicStackBuffer(const DynamicStackBuffer &other) = delete;
+ DynamicStackBuffer(DynamicStackBuffer &&other) = delete;
+ DynamicStackBuffer &operator=(const DynamicStackBuffer &other) = delete;
+ DynamicStackBuffer &operator=(DynamicStackBuffer &&other) = delete;
+
+ void *buffer() const
+ {
+ return buffer_;
+ }
+};
+
/**
* This can be used by container constructors. A parameter of this type should be used to indicate
* that the constructor does not construct the elements.
diff --git a/source/blender/blenlib/BLI_mesh_boolean.hh b/source/blender/blenlib/BLI_mesh_boolean.hh
index 94b2694893b..a55b2175527 100644
--- a/source/blender/blenlib/BLI_mesh_boolean.hh
+++ b/source/blender/blenlib/BLI_mesh_boolean.hh
@@ -59,6 +59,7 @@ IMesh boolean_mesh(IMesh &imesh,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMesh *imesh_triangulated,
IMeshArena *arena);
@@ -72,6 +73,7 @@ IMesh boolean_trimesh(IMesh &tm_in,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMeshArena *arena);
} // namespace blender::meshintersect
diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh
index 018f080e633..4113085a1e3 100644
--- a/source/blender/blenlib/BLI_multi_value_map.hh
+++ b/source/blender/blenlib/BLI_multi_value_map.hh
@@ -104,6 +104,22 @@ template<typename Key, typename Value> class MultiValueMap {
}
/**
+ * Get a mutable span to all the values that are stored for the given key.
+ */
+ MutableSpan<Value> lookup(const Key &key)
+ {
+ return this->lookup_as(key);
+ }
+ template<typename ForwardKey> MutableSpan<Value> lookup_as(const ForwardKey &key)
+ {
+ Vector<Value> *vector = map_.lookup_ptr_as(key);
+ if (vector != nullptr) {
+ return vector->as_mutable_span();
+ }
+ return {};
+ }
+
+ /**
* Note: This signature will change when the implementation changes.
*/
typename MapType::ItemIterator items() const
diff --git a/source/blender/blenlib/BLI_resource_collector.hh b/source/blender/blenlib/BLI_resource_collector.hh
index ecae9b8c682..70804ceb1f1 100644
--- a/source/blender/blenlib/BLI_resource_collector.hh
+++ b/source/blender/blenlib/BLI_resource_collector.hh
@@ -130,9 +130,10 @@ class ResourceCollector : NonCopyable, NonMovable {
*/
template<typename T, typename... Args> T &construct(const char *name, Args &&... args)
{
- T *value = m_allocator.construct<T>(std::forward<Args>(args)...);
- this->add(destruct_ptr<T>(value), name);
- return *value;
+ destruct_ptr<T> value_ptr = m_allocator.construct<T>(std::forward<Args>(args)...);
+ T &value_ref = *value_ptr;
+ this->add(std::move(value_ptr), name);
+ return value_ref;
}
/**
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 5f55efe3f63..fcc6d6f754b 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -132,12 +132,11 @@ template<typename T> class Span {
}
/**
- * Support implicit conversions like the ones below:
+ * Support implicit conversions like the one below:
* Span<T *> -> Span<const T *>
*/
-
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
- constexpr Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
+ constexpr Span(Span<U> span) : data_(static_cast<const T *>(span.data())), size_(span.size())
{
}
@@ -418,6 +417,19 @@ template<typename T> class Span {
return Span<NewT>(reinterpret_cast<const NewT *>(data_), new_size);
}
+ friend bool operator==(const Span<T> a, const Span<T> b)
+ {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ return std::equal(a.begin(), a.end(), b.begin());
+ }
+
+ friend bool operator!=(const Span<T> a, const Span<T> b)
+ {
+ return !(a == b);
+ }
+
/**
* A debug utility to print the content of the Span. Every element will be printed on a
* separate line using the given callback.
@@ -467,11 +479,27 @@ template<typename T> class MutableSpan {
{
}
+ /**
+ * Support implicit conversions like the one below:
+ * MutableSpan<T *> -> MutableSpan<const T *>
+ */
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ constexpr MutableSpan(MutableSpan<U> span)
+ : data_(static_cast<T *>(span.data())), size_(span.size())
+ {
+ }
+
constexpr operator Span<T>() const
{
return Span<T>(data_, size_);
}
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ constexpr operator Span<U>() const
+ {
+ return Span<U>(static_cast<const U *>(data_), size_);
+ }
+
/**
* Returns the number of elements in the array.
*/
@@ -653,12 +681,13 @@ template<typename T> class MutableSpan {
/**
* Returns a new span to the same underlying memory buffer. No conversions are done.
+ * The caller is responsible for making sure that the type cast is valid.
*/
template<typename NewT> constexpr MutableSpan<NewT> cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
- return MutableSpan<NewT>(reinterpret_cast<NewT *>(data_), new_size);
+ return MutableSpan<NewT>((NewT *)data_, new_size);
}
};
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 46fb096599f..1057e71a6b2 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -90,7 +90,7 @@ bool BLI_uniquename(struct ListBase *list,
void *vlink,
const char *defname,
char delim,
- int name_offs,
+ int name_offset,
size_t len);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index fe6d54ae9e5..eefacd5d64f 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -879,6 +879,16 @@ class Vector {
return IndexRange(this->size());
}
+ friend bool operator==(const Vector &a, const Vector &b)
+ {
+ return a.as_span() == b.as_span();
+ }
+
+ friend bool operator!=(const Vector &a, const Vector &b)
+ {
+ return !(a == b);
+ }
+
/**
* Print some debug information about the vector.
*/
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 2da2bbbc2a5..17ee0eecc6b 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -27,13 +27,13 @@
#include "MEM_guardedalloc.h"
-#include "BLI_array_utils.h"
-
#include "BLI_alloca.h"
+#include "BLI_math_base.h"
+#include "BLI_strict_flags.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
-#include "BLI_strict_flags.h"
+#include "BLI_array_utils.h"
/**
*In-place array reverse.
@@ -318,3 +318,94 @@ bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_st
}
return true;
}
+
+/**
+ * Smart function to sample a rect spiraling outside.
+ * Nice for selection ID.
+ *
+ * \param arr_shape: dimensions [w, h].
+ * \param center: coordinates [x, y] indicating where to start traversing.
+ */
+bool _bli_array_iter_spiral_square(const void *arr_v,
+ const int arr_shape[2],
+ size_t elem_size,
+ const int center[2],
+ bool (*test_fn)(const void *arr_item, void *user_data),
+ void *user_data)
+{
+ BLI_assert(center[0] >= 0 && center[1] >= 0 && center[0] < arr_shape[0] &&
+ center[1] < arr_shape[1]);
+
+ const char *arr = arr_v;
+ const int stride[2] = {arr_shape[1] * (int)elem_size, (int)elem_size};
+
+ /* Test center first. */
+ int ofs[2] = {center[0] * stride[0], center[1] * stride[1]};
+ if (test_fn(arr + ofs[0] + ofs[1], user_data)) {
+ return true;
+ }
+
+ /* #steps_in and #steps_out are the "diameters" of the inscribed and circumscribed squares in the
+ * rectangle. Each step smaller than #steps_in does not need to check bounds. */
+ int steps_in, steps_out;
+ {
+ int x_minus = center[0];
+ int x_plus = arr_shape[0] - center[0] - 1;
+ int y_minus = center[1];
+ int y_plus = arr_shape[1] - center[1] - 1;
+
+ steps_in = 2 * min_iiii(x_minus, x_plus, y_minus, y_plus);
+ steps_out = 2 * max_iiii(x_minus, x_plus, y_minus, y_plus);
+ }
+
+ /* For check_bounds. */
+ int limits[2] = {(arr_shape[0] - 1) * stride[0], stride[0] - stride[1]};
+
+ int steps = 0;
+ while (steps < steps_out) {
+ steps += 2;
+
+ /* Move one step to the diagonal of the negative quadrant. */
+ ofs[0] -= stride[0];
+ ofs[1] -= stride[1];
+
+ bool check_bounds = steps > steps_in;
+
+ /* sign: 0 neg; 1 pos; */
+ for (int sign = 2; sign--;) {
+ /* axis: 0 x; 1 y; */
+ for (int axis = 2; axis--;) {
+ int ofs_step = stride[axis];
+ if (!sign) {
+ ofs_step *= -1;
+ }
+
+ int ofs_iter = ofs[axis] + ofs_step;
+ int ofs_dest = ofs[axis] + steps * ofs_step;
+ int ofs_other = ofs[!axis];
+
+ ofs[axis] = ofs_dest;
+ if (check_bounds) {
+ if (ofs_other < 0 || ofs_other > limits[!axis]) {
+ /* Out of bounds. */
+ continue;
+ }
+
+ CLAMP(ofs_iter, 0, limits[axis]);
+ CLAMP(ofs_dest, 0, limits[axis]);
+ }
+
+ while (true) {
+ if (test_fn(arr + ofs_other + ofs_iter, user_data)) {
+ return true;
+ }
+ if (ofs_iter == ofs_dest) {
+ break;
+ }
+ ofs_iter += ofs_step;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 39945960e68..6481fac5a14 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -180,6 +180,18 @@ MINLINE double interpd(double target, double origin, double fac)
return (fac * target) + (1.0f - fac) * origin;
}
+MINLINE float ratiof(float min, float max, float pos)
+{
+ float range = max - min;
+ return range == 0 ? 0 : ((pos - min) / range);
+}
+
+MINLINE double ratiod(double min, double max, double pos)
+{
+ double range = max - min;
+ return range == 0 ? 0 : ((pos - min) / range);
+}
+
/* used for zoom values*/
MINLINE float power_of_2(float val)
{
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index b460d75d77f..2ada05d2965 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2140,6 +2140,16 @@ void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
}
}
+void mat4_to_rot(float rot[3][3], const float wmat[4][4])
+{
+ normalize_v3_v3(rot[0], wmat[0]);
+ normalize_v3_v3(rot[1], wmat[1]);
+ normalize_v3_v3(rot[2], wmat[2]);
+ if (UNLIKELY(is_negative_m3(rot))) {
+ negate_m3(rot);
+ }
+}
+
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
{
float mat3[3][3]; /* wmat -> 3x3 */
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index fcf5c5bfad3..bc12ff1a652 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -408,6 +408,7 @@ class Cell {
void add_patch(int p)
{
patches_.add(p);
+ zero_volume_ = false; /* If it was true before, it no longer is. */
}
const Set<int> &patches() const
@@ -2484,29 +2485,14 @@ static void test_tri_inside_shapes(const IMesh &tm,
}
/**
- * Use the RayCast method for deciding if a triangle of the
- * mesh is supposed to be included or excluded in the boolean result,
- * and return the mesh that is the boolean result.
- * The reason this is done on a triangle-by-triangle basis is that
- * when the input is not PWN, some patches can be both inside and outside
- * some shapes (e.g., a plane cutting through Suzanne's open eyes).
+ * Return a BVH Tree that contains all of the triangles of \a tm.
+ * The caller must free it.
+ * (We could possible reuse the BVH tree(s) built in TriOverlaps,
+ * in the mesh intersect function. A future TODO.)
*/
-static IMesh raycast_boolean(const IMesh &tm,
- BoolOpType op,
- int nshapes,
- std::function<int(int)> shape_fn,
- IMeshArena *arena)
+static BVHTree *raycast_tree(const IMesh &tm)
{
- constexpr int dbg_level = 0;
- if (dbg_level > 0) {
- std::cout << "RAYCAST_BOOLEAN\n";
- }
- IMesh ans;
-
- /* Build a BVH tree of tm's triangles.
- * We could possibly reuse the BVH tree(s) build in TriOverlaps in
- * the mesh intersect function. A future TODO. */
- BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 8);
+ BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 4, 6);
for (int i : tm.face_index_range()) {
const Face *f = tm.face(i);
float t_cos[9];
@@ -2519,7 +2505,70 @@ static IMesh raycast_boolean(const IMesh &tm,
BLI_bvhtree_insert(tree, i, t_cos, 3);
}
BLI_bvhtree_balance(tree);
+ return tree;
+}
+
+/**
+ * Should a face with given shape and given winding array be removed for given boolean op?
+ * Also return true in *r_do_flip if it retained by normals need to be flipped.
+ */
+static bool raycast_test_remove(BoolOpType op, Array<int> &winding, int shape, bool *r_do_flip)
+{
+ constexpr int dbg_level = 0;
+ /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0
+ * and winding[shape] == 1. If the flags are different, this patch should be in the output.
+ * Also, if this is a Difference and the shape isn't the first one, need to flip the normals.
+ */
+ winding[shape] = 0;
+ bool in_output_volume_0 = apply_bool_op(op, winding);
+ winding[shape] = 1;
+ bool in_output_volume_1 = apply_bool_op(op, winding);
+ bool do_remove = in_output_volume_0 == in_output_volume_1;
+ bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0;
+ if (dbg_level > 0) {
+ std::cout << "winding = ";
+ for (int i = 0; i < winding.size(); ++i) {
+ std::cout << winding[i] << " ";
+ }
+ std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n";
+ std::cout << " remove=" << do_remove << ", flip=" << do_flip << "\n";
+ }
+ *r_do_flip = do_flip;
+ return do_remove;
+}
+
+/** Add triangle a flipped version of tri to out_faces. */
+static void raycast_add_flipped(Vector<Face *> &out_faces, Face &tri, IMeshArena *arena)
+{
+ Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]};
+ Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]};
+ Array<bool> flipped_is_intersect = {
+ tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]};
+ Face *flipped_f = arena->add_face(flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect);
+ out_faces.append(flipped_f);
+}
+
+/**
+ * Use the RayCast method for deciding if a triangle of the
+ * mesh is supposed to be included or excluded in the boolean result,
+ * and return the mesh that is the boolean result.
+ * The reason this is done on a triangle-by-triangle basis is that
+ * when the input is not PWN, some patches can be both inside and outside
+ * some shapes (e.g., a plane cutting through Suzanne's open eyes).
+ */
+static IMesh raycast_tris_boolean(const IMesh &tm,
+ BoolOpType op,
+ int nshapes,
+ std::function<int(int)> shape_fn,
+ IMeshArena *arena)
+{
+ constexpr int dbg_level = 0;
+ if (dbg_level > 0) {
+ std::cout << "RAYCAST_TRIS_BOOLEAN\n";
+ }
+ IMesh ans;
+ BVHTree *tree = raycast_tree(tm);
Vector<Face *> out_faces;
out_faces.reserve(tm.face_size());
Array<float> in_shape(nshapes, 0);
@@ -2541,47 +2590,95 @@ static IMesh raycast_boolean(const IMesh &tm,
* gives good results, but when shape is a cutter in a Difference
* operation, we want to be pretty sure that the point is inside other_shape.
* E.g., T75827.
+ * Also, when the operation is intersection, we also want high confidence.
*/
- bool need_high_confidence = (op == BoolOpType::Difference) && (shape != 0);
+ bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) ||
+ op == BoolOpType::Intersect;
bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f);
if (dbg_level > 0) {
std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape "
- << other_shape << "\n";
+ << other_shape << " val = " << in_shape[other_shape] << "\n";
}
winding[other_shape] = inside;
}
- /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0
- * and winding[shape] == 1. If the flags are different, this patch should be in the output.
- * Also, if this is a Difference and the shape isn't the first one, need to flip the normals.
- */
- winding[shape] = 0;
- bool in_output_volume_0 = apply_bool_op(op, winding);
- winding[shape] = 1;
- bool in_output_volume_1 = apply_bool_op(op, winding);
- bool do_remove = in_output_volume_0 == in_output_volume_1;
- bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0;
- if (dbg_level > 0) {
- std::cout << "winding = ";
- for (int i = 0; i < nshapes; ++i) {
- std::cout << winding[i] << " ";
- }
- std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n";
- std::cout << "result for tri " << t << ": remove=" << do_remove << ", flip=" << do_flip
- << "\n";
- }
+ bool do_flip;
+ bool do_remove = raycast_test_remove(op, winding, shape, &do_flip);
if (!do_remove) {
if (!do_flip) {
out_faces.append(&tri);
}
else {
- /* We need flipped version of tri. */
- Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]};
- Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]};
- Array<bool> flipped_is_intersect = {
- tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]};
- Face *flipped_f = arena->add_face(
- flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect);
- out_faces.append(flipped_f);
+ raycast_add_flipped(out_faces, tri, arena);
+ }
+ }
+ }
+ BLI_bvhtree_free(tree);
+ ans.set_faces(out_faces);
+ return ans;
+}
+
+/* This is (sometimes much faster) version of raycast boolean
+ * that does it per patch rather than per triangle.
+ * It may fail in cases where raycast_tri_boolean will succeed,
+ * but the latter can be very slow on huge meshes. */
+static IMesh raycast_patches_boolean(const IMesh &tm,
+ BoolOpType op,
+ int nshapes,
+ std::function<int(int)> shape_fn,
+ const PatchesInfo &pinfo,
+ IMeshArena *arena)
+{
+ constexpr int dbg_level = 0;
+ if (dbg_level > 0) {
+ std::cout << "RAYCAST_PATCHES_BOOLEAN\n";
+ }
+ IMesh ans;
+ BVHTree *tree = raycast_tree(tm);
+ Vector<Face *> out_faces;
+ out_faces.reserve(tm.face_size());
+ Array<float> in_shape(nshapes, 0);
+ Array<int> winding(nshapes, 0);
+ for (int p : pinfo.index_range()) {
+ const Patch &patch = pinfo.patch(p);
+ /* For test triangle, choose one in the middle of patch list
+ * as the ones near the beginning may be very near other patches. */
+ int test_t_index = patch.tri(patch.tot_tri() / 2);
+ Face &tri_test = *tm.face(test_t_index);
+ /* Assume all triangles in a patch are in the same shape. */
+ int shape = shape_fn(tri_test.orig);
+ if (dbg_level > 0) {
+ std::cout << "process patch " << p << " = " << patch << "\n";
+ std::cout << "test tri = " << test_t_index << " = " << &tri_test << "\n";
+ std::cout << "shape = " << shape << "\n";
+ }
+ if (shape == -1) {
+ continue;
+ }
+ test_tri_inside_shapes(tm, shape_fn, nshapes, test_t_index, tree, in_shape);
+ for (int other_shape = 0; other_shape < nshapes; ++other_shape) {
+ if (other_shape == shape) {
+ continue;
+ }
+ bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) ||
+ op == BoolOpType::Intersect;
+ bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f);
+ if (dbg_level > 0) {
+ std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape "
+ << other_shape << " val = " << in_shape[other_shape] << "\n";
+ }
+ winding[other_shape] = inside;
+ }
+ bool do_flip;
+ bool do_remove = raycast_test_remove(op, winding, shape, &do_flip);
+ if (!do_remove) {
+ for (int t : patch.tris()) {
+ Face *f = tm.face(t);
+ if (!do_flip) {
+ out_faces.append(f);
+ }
+ else {
+ raycast_add_flipped(out_faces, *f, arena);
+ }
}
}
}
@@ -3341,6 +3438,7 @@ IMesh boolean_trimesh(IMesh &tm_in,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMeshArena *arena)
{
constexpr int dbg_level = 0;
@@ -3391,7 +3489,13 @@ IMesh boolean_trimesh(IMesh &tm_in,
if (dbg_level > 0) {
std::cout << "Input is not PWN, using raycast method\n";
}
- tm_out = raycast_boolean(tm_si, op, nshapes, shape_fn, arena);
+ if (hole_tolerant) {
+ tm_out = raycast_tris_boolean(tm_si, op, nshapes, shape_fn, arena);
+ }
+ else {
+ PatchesInfo pinfo = find_patches(tm_si, tm_si_topo);
+ tm_out = raycast_patches_boolean(tm_si, op, nshapes, shape_fn, pinfo, arena);
+ }
# ifdef PERFDEBUG
double raycast_time = PIL_check_seconds_timer();
std::cout << " raycast_boolean done, time = " << raycast_time - pwn_time << "\n";
@@ -3486,6 +3590,7 @@ IMesh boolean_mesh(IMesh &imesh,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMesh *imesh_triangulated,
IMeshArena *arena)
{
@@ -3519,7 +3624,7 @@ IMesh boolean_mesh(IMesh &imesh,
if (dbg_level > 1) {
write_obj_mesh(*tm_in, "boolean_tm_in");
}
- IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena);
+ IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, hole_tolerant, arena);
# ifdef PERFDEBUG
double bool_tri_time = PIL_check_seconds_timer();
std::cout << "boolean_trimesh done, time = " << bool_tri_time - tri_time << "\n";
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index bb00755e901..287334a34ee 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -377,7 +377,7 @@ int BLI_exists(const char *path)
struct stat st;
BLI_assert(!BLI_path_is_rel(path));
if (stat(path, &st)) {
- return (0);
+ return 0;
}
#endif
return (st.st_mode);
diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc
index a09aa7a4bc2..44baff1f5e3 100644
--- a/source/blender/blenlib/intern/string_search.cc
+++ b/source/blender/blenlib/intern/string_search.cc
@@ -395,6 +395,7 @@ void extract_normalized_words(StringRef str,
struct SearchItem {
blender::Span<blender::StringRef> normalized_words;
+ int length;
void *user_data;
};
@@ -416,8 +417,10 @@ void BLI_string_search_add(StringSearch *search, const char *str, void *user_dat
{
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});
+ StringRef str_ref{str};
+ string_search::extract_normalized_words(str_ref, search->allocator, words);
+ search->items.append(
+ {search->allocator.construct_array_copy(words.as_span()), (int)str_ref.size(), user_data});
}
/**
@@ -453,7 +456,15 @@ int BLI_string_search_query(StringSearch *search, const char *query, void ***r_d
* 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);
+ MutableSpan<int> indices = result_indices_by_score.lookup(score);
+ if (score == found_scores[0]) {
+ /* Sort items with best score by length. Shorter items are more likely the ones you are
+ * looking for. This also ensures that exact matches will be at the top, even if the query is
+ * a substring of another item. */
+ std::sort(indices.begin(), indices.end(), [&](int a, int b) {
+ return search->items[a].length < search->items[b].length;
+ });
+ }
sorted_result_indices.extend(indices);
}
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index dbeb75570fb..c847f7e1921 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -333,27 +333,22 @@ bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
return false;
}
-/* little helper macro for BLI_uniquename */
-#ifndef GIVE_STRADDR
-# define GIVE_STRADDR(data, offset) (((char *)data) + offset)
-#endif
-
/**
* Generic function to set a unique name. It is only designed to be used in situations
* where the name is part of the struct.
*
* For places where this is used, see constraint.c for example...
*
- * \param name_offs: should be calculated using offsetof(structname, membername)
- * macro from stddef.h
+ * \param name_offset: should be calculated using `offsetof(structname, membername)`
+ * macro from `stddef.h`
*/
-static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
+static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset)
{
Link *link;
for (link = list->first; link; link = link->next) {
if (link != vlink) {
- if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
+ if (STREQ(POINTER_OFFSET((const char *)link, name_offset), name)) {
return true;
}
}
@@ -367,9 +362,9 @@ static bool uniquename_unique_check(void *arg, const char *name)
struct {
ListBase *lb;
void *vlink;
- int name_offs;
+ int name_offset;
} *data = arg;
- return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
+ return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
}
/**
@@ -380,20 +375,20 @@ static bool uniquename_unique_check(void *arg, const char *name)
* \param vlink: The block to check the name for
* \param defname: To initialize block name if latter is empty
* \param delim: Delimits numeric suffix in name
- * \param name_offs: Offset of name within block structure
+ * \param name_offset: Offset of name within block structure
* \param name_len: Maximum length of name area
*/
bool BLI_uniquename(
- ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
+ ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
{
struct {
ListBase *lb;
void *vlink;
- int name_offs;
+ int name_offset;
} data;
data.lb = list;
data.vlink = vlink;
- data.name_offs = name_offs;
+ data.name_offset = name_offset;
BLI_assert(name_len > 1);
@@ -402,8 +397,12 @@ bool BLI_uniquename(
return false;
}
- return BLI_uniquename_cb(
- uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
+ return BLI_uniquename_cb(uniquename_unique_check,
+ &data,
+ defname,
+ delim,
+ POINTER_OFFSET(vlink, name_offset),
+ name_len);
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
index a35fbf70711..977e5dba497 100644
--- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
+++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
@@ -1,6 +1,7 @@
/* Apache License, Version 2.0 */
#include "BLI_linear_allocator.hh"
+#include "BLI_rand.hh"
#include "BLI_strict_flags.h"
#include "testing/testing.h"
@@ -78,7 +79,7 @@ TEST(linear_allocator, Construct)
LinearAllocator<> allocator;
std::array<int, 5> values = {1, 2, 3, 4, 5};
- Vector<int> *vector = allocator.construct<Vector<int>>(values);
+ Vector<int> *vector = allocator.construct<Vector<int>>(values).release();
EXPECT_EQ(vector->size(), 5);
EXPECT_EQ((*vector)[3], 4);
vector->~Vector();
@@ -115,4 +116,24 @@ TEST(linear_allocator, ConstructArrayCopy)
EXPECT_EQ(span2[2], 3);
}
+TEST(linear_allocator, AllocateLarge)
+{
+ LinearAllocator<> allocator;
+ void *buffer1 = allocator.allocate(1024 * 1024, 8);
+ void *buffer2 = allocator.allocate(1024 * 1024, 8);
+ EXPECT_NE(buffer1, buffer2);
+}
+
+TEST(linear_allocator, ManyAllocations)
+{
+ LinearAllocator<> allocator;
+ RandomNumberGenerator rng;
+ for (int i = 0; i < 1000; i++) {
+ int size = rng.get_int32(10000);
+ int alignment = 1 << (rng.get_int32(7));
+ void *buffer = allocator.allocate(size, alignment);
+ EXPECT_NE(buffer, nullptr);
+ }
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_map_test.cc b/source/blender/blenlib/tests/BLI_map_test.cc
index 323ced87d9e..70c1887a527 100644
--- a/source/blender/blenlib/tests/BLI_map_test.cc
+++ b/source/blender/blenlib/tests/BLI_map_test.cc
@@ -565,6 +565,28 @@ TEST(map, AddOrModifyExceptions)
EXPECT_ANY_THROW({ map.add_or_modify(3, create_fn, modify_fn); });
}
+namespace {
+enum class TestEnum {
+ A = 0,
+ B = 1,
+ C = 2,
+ D = 1,
+};
+}
+
+TEST(map, EnumKey)
+{
+ Map<TestEnum, int> map;
+ map.add(TestEnum::A, 4);
+ map.add(TestEnum::B, 6);
+ EXPECT_EQ(map.lookup(TestEnum::A), 4);
+ EXPECT_EQ(map.lookup(TestEnum::B), 6);
+ EXPECT_EQ(map.lookup(TestEnum::D), 6);
+ EXPECT_FALSE(map.contains(TestEnum::C));
+ map.lookup(TestEnum::D) = 10;
+ EXPECT_EQ(map.lookup(TestEnum::B), 10);
+}
+
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/
diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
index e503ef8f264..d759f0c3be4 100644
--- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
@@ -113,7 +113,7 @@ TEST(boolean_trimesh, Empty)
{
IMeshArena arena;
IMesh in;
- IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, &arena);
+ IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, false, &arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 0);
EXPECT_EQ(out.face_size(), 0);
@@ -141,7 +141,8 @@ TEST(boolean_trimesh, TetTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::None, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 11);
EXPECT_EQ(out.face_size(), 20);
@@ -150,7 +151,8 @@ TEST(boolean_trimesh, TetTetTrimesh)
}
IMeshBuilder mb2(spec);
- IMesh out2 = boolean_trimesh(mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb2.arena);
+ IMesh out2 = boolean_trimesh(
+ mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb2.arena);
out2.populate_vert();
EXPECT_EQ(out2.vert_size(), 10);
EXPECT_EQ(out2.face_size(), 16);
@@ -160,7 +162,13 @@ TEST(boolean_trimesh, TetTetTrimesh)
IMeshBuilder mb3(spec);
IMesh out3 = boolean_trimesh(
- mb3.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena);
+ mb3.imesh,
+ BoolOpType::Union,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ false,
+ false,
+ &mb3.arena);
out3.populate_vert();
EXPECT_EQ(out3.vert_size(), 10);
EXPECT_EQ(out3.face_size(), 16);
@@ -170,7 +178,13 @@ TEST(boolean_trimesh, TetTetTrimesh)
IMeshBuilder mb4(spec);
IMesh out4 = boolean_trimesh(
- mb4.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena);
+ mb4.imesh,
+ BoolOpType::Union,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ true,
+ false,
+ &mb4.arena);
out4.populate_vert();
EXPECT_EQ(out4.vert_size(), 10);
EXPECT_EQ(out4.face_size(), 16);
@@ -180,7 +194,13 @@ TEST(boolean_trimesh, TetTetTrimesh)
IMeshBuilder mb5(spec);
IMesh out5 = boolean_trimesh(
- mb5.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena);
+ mb5.imesh,
+ BoolOpType::Intersect,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ false,
+ false,
+ &mb5.arena);
out5.populate_vert();
EXPECT_EQ(out5.vert_size(), 4);
EXPECT_EQ(out5.face_size(), 4);
@@ -195,6 +215,7 @@ TEST(boolean_trimesh, TetTetTrimesh)
2,
[](int t) { return t < 4 ? 0 : 1; },
false,
+ false,
&mb6.arena);
out6.populate_vert();
EXPECT_EQ(out6.vert_size(), 6);
@@ -210,6 +231,7 @@ TEST(boolean_trimesh, TetTetTrimesh)
2,
[](int t) { return t < 4 ? 1 : 0; },
false,
+ false,
&mb7.arena);
out7.populate_vert();
EXPECT_EQ(out7.vert_size(), 8);
@@ -241,7 +263,8 @@ TEST(boolean_trimesh, TetTet2Trimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 10);
EXPECT_EQ(out.face_size(), 16);
@@ -284,7 +307,8 @@ TEST(boolean_trimesh, CubeTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 14);
EXPECT_EQ(out.face_size(), 24);
@@ -316,7 +340,13 @@ TEST(boolean_trimesh, BinaryTetTetTrimesh)
IMeshBuilder mb(spec);
IMesh out = boolean_trimesh(
- mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena);
+ mb.imesh,
+ BoolOpType::Intersect,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ false,
+ false,
+ &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 4);
EXPECT_EQ(out.face_size(), 4);
@@ -347,7 +377,8 @@ TEST(boolean_trimesh, TetTetCoplanarTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 5);
EXPECT_EQ(out.face_size(), 6);
@@ -378,7 +409,8 @@ TEST(boolean_trimesh, TetInsideTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 4);
EXPECT_EQ(out.face_size(), 4);
@@ -409,7 +441,8 @@ TEST(boolean_trimesh, TetBesideTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 8);
EXPECT_EQ(out.face_size(), 8);
@@ -445,7 +478,13 @@ TEST(boolean_trimesh, DegenerateTris)
IMeshBuilder mb(spec);
IMesh out = boolean_trimesh(
- mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena);
+ mb.imesh,
+ BoolOpType::Intersect,
+ 2,
+ [](int t) { return t < 5 ? 0 : 1; },
+ false,
+ false,
+ &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 4);
EXPECT_EQ(out.face_size(), 4);
@@ -477,7 +516,7 @@ TEST(boolean_polymesh, TetTet)
IMeshBuilder mb(spec);
IMesh out = boolean_mesh(
- mb.imesh, BoolOpType::None, 1, all_shape_zero, true, nullptr, &mb.arena);
+ mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, nullptr, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 11);
EXPECT_EQ(out.face_size(), 13);
@@ -492,6 +531,7 @@ TEST(boolean_polymesh, TetTet)
2,
[](int t) { return t < 4 ? 0 : 1; },
false,
+ false,
nullptr,
&mb2.arena);
out2.populate_vert();
@@ -540,7 +580,7 @@ TEST(boolean_polymesh, CubeCube)
write_obj_mesh(mb.imesh, "cube_cube_in");
}
IMesh out = boolean_mesh(
- mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena);
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 20);
EXPECT_EQ(out.face_size(), 12);
@@ -555,6 +595,7 @@ TEST(boolean_polymesh, CubeCube)
2,
[](int t) { return t < 6 ? 0 : 1; },
false,
+ false,
nullptr,
&mb2.arena);
out2.populate_vert();
@@ -597,7 +638,7 @@ TEST(boolean_polymesh, CubeCone)
IMeshBuilder mb(spec);
IMesh out = boolean_mesh(
- mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena);
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 14);
EXPECT_EQ(out.face_size(), 12);
@@ -646,6 +687,7 @@ TEST(boolean_polymesh, CubeCubeCoplanar)
2,
[](int t) { return t < 6 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -684,6 +726,7 @@ TEST(boolean_polymesh, TetTeTCoplanarDiff)
2,
[](int t) { return t < 4 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -734,6 +777,7 @@ TEST(boolean_polymesh, CubeCubeStep)
2,
[](int t) { return t < 6 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -784,6 +828,7 @@ TEST(boolean_polymesh, CubeCyl4)
2,
[](int t) { return t < 6 ? 1 : 0; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -855,6 +900,7 @@ TEST(boolean_polymesh, CubeCubesubdivDiff)
2,
[](int t) { return t < 16 ? 1 : 0; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -896,6 +942,7 @@ TEST(boolean_polymesh, CubePlane)
2,
[](int t) { return t >= 1 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
diff --git a/source/blender/blenlib/tests/BLI_multi_value_map_test.cc b/source/blender/blenlib/tests/BLI_multi_value_map_test.cc
index 7501fbe0d87..a910f2935d4 100644
--- a/source/blender/blenlib/tests/BLI_multi_value_map_test.cc
+++ b/source/blender/blenlib/tests/BLI_multi_value_map_test.cc
@@ -29,6 +29,27 @@ TEST(multi_value_map, LookupExistant)
EXPECT_EQ(map.lookup(3)[0], 6);
}
+TEST(multi_value_map, LookupMutable)
+{
+ MultiValueMap<int, int> map;
+ map.add(1, 2);
+ map.add(4, 5);
+ map.add(4, 6);
+ map.add(6, 7);
+
+ MutableSpan<int> span = map.lookup(4);
+ EXPECT_EQ(span.size(), 2);
+ span[0] = 10;
+ span[1] = 20;
+
+ map.add(4, 5);
+ MutableSpan<int> new_span = map.lookup(4);
+ EXPECT_EQ(new_span.size(), 3);
+ EXPECT_EQ(new_span[0], 10);
+ EXPECT_EQ(new_span[1], 20);
+ EXPECT_EQ(new_span[2], 5);
+}
+
TEST(multi_value_map, AddMultiple)
{
MultiValueMap<int, int> map;
diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc
index 002c97b0c7d..5e3c6a1b680 100644
--- a/source/blender/blenlib/tests/BLI_span_test.cc
+++ b/source/blender/blenlib/tests/BLI_span_test.cc
@@ -392,4 +392,33 @@ TEST(span, Constexpr)
EXPECT_EQ(span.slice(1, 2).size(), 2);
}
+TEST(span, ImplicitConversions)
+{
+ BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int>, Span<int>>), "");
+ BLI_STATIC_ASSERT((std::is_convertible_v<Span<int *>, Span<const int *>>), "");
+ BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int *>, Span<int *>>), "");
+ BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int *>, Span<const int *>>), "");
+ BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int *>, MutableSpan<const int *>>), "");
+ BLI_STATIC_ASSERT((!std::is_convertible_v<MutableSpan<const int *>, MutableSpan<int *>>), "");
+ BLI_STATIC_ASSERT((!std::is_convertible_v<Span<const int *>, Span<int *>>), "");
+ BLI_STATIC_ASSERT((!std::is_convertible_v<Span<int *>, MutableSpan<const int *>>), "");
+}
+
+TEST(span, Comparison)
+{
+ std::array<int, 3> a = {3, 4, 5};
+ std::array<int, 4> b = {3, 4, 5, 6};
+
+ EXPECT_FALSE(Span(a) == Span(b));
+ EXPECT_FALSE(Span(b) == Span(a));
+ EXPECT_TRUE(Span(a) == Span(b).take_front(3));
+ EXPECT_TRUE(Span(a) == Span(a));
+ EXPECT_TRUE(Span(b) == Span(b));
+
+ EXPECT_TRUE(Span(a) != Span(b));
+ EXPECT_TRUE(Span(b) != Span(a));
+ EXPECT_FALSE(Span(a) != Span(b).take_front(3));
+ EXPECT_FALSE(Span(a) != Span(a));
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c7f02de21ea..09f4c405613 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -182,6 +182,8 @@ struct LibraryLink_Params {
struct Main *bmain;
/** Options for linking, used for instantiating. */
int flag;
+ /** Additional tag for #ID.tag. */
+ int id_tag_extra;
/** Context for instancing objects (optional, no instantiation will be performed when NULL). */
struct {
/** The scene in which to instantiate objects/collections. */
@@ -195,10 +197,12 @@ struct LibraryLink_Params {
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag);
+ const int flag,
+ const int id_tag_extra);
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
struct Main *bmain,
const int flag,
+ const int id_tag_extra,
struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d);
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
index 7261db5d3a6..f3fc1453461 100644
--- a/source/blender/blenloader/intern/blend_validate.c
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -60,7 +60,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
blo_split_main(&mainlist, bmain);
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int i = set_listbasepointers(bmain, lbarray);
while (i--) {
for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index c0293c1f8f2..f97f6f65551 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -449,7 +449,7 @@ static void oldnewmap_free(OldNewMap *onm)
static void add_main_to_main(Main *mainvar, Main *from)
{
- ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX], *fromarray[INDEX_ID_MAX];
int a;
set_listbasepointers(mainvar, lbarray);
@@ -517,7 +517,7 @@ void blo_split_main(ListBase *mainlist, Main *main)
lib_main_array[i] = libmain;
}
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
i = set_listbasepointers(main, lbarray);
while (i--) {
ID *id = lbarray[i]->first;
@@ -555,6 +555,23 @@ static void read_file_version(FileData *fd, Main *main)
}
}
+static bool blo_bhead_is_id(const BHead *bhead)
+{
+ /* BHead codes are four bytes (like 'ENDB', 'TEST', etc.), but if the two most-significant bytes
+ * are zero, the values actually indicate an ID type. */
+ return bhead->code <= 0xFFFF;
+}
+
+static bool blo_bhead_is_id_valid_type(const BHead *bhead)
+{
+ if (!blo_bhead_is_id(bhead)) {
+ return false;
+ }
+
+ const short id_type_code = bhead->code & 0xFFFF;
+ return BKE_idtype_idcode_is_valid(id_type_code);
+}
+
#ifdef USE_GHASH_BHEAD
static void read_file_bhead_idname_map_create(FileData *fd)
{
@@ -568,8 +585,9 @@ static void read_file_bhead_idname_map_create(FileData *fd)
for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
if (code_prev != bhead->code) {
code_prev = bhead->code;
- is_link = BKE_idtype_idcode_is_valid(code_prev) ? BKE_idtype_idcode_is_linkable(code_prev) :
- false;
+ is_link = blo_bhead_is_id_valid_type(bhead) ?
+ BKE_idtype_idcode_is_linkable((short)code_prev) :
+ false;
}
if (is_link) {
@@ -584,8 +602,9 @@ static void read_file_bhead_idname_map_create(FileData *fd)
for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
if (code_prev != bhead->code) {
code_prev = bhead->code;
- is_link = BKE_idtype_idcode_is_valid(code_prev) ? BKE_idtype_idcode_is_linkable(code_prev) :
- false;
+ is_link = blo_bhead_is_id_valid_type(bhead) ?
+ BKE_idtype_idcode_is_linkable((short)code_prev) :
+ false;
}
if (is_link) {
@@ -967,15 +986,15 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
{
- return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
+ return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
}
/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
{
- BLI_assert(BKE_idtype_idcode_is_valid(bhead->code));
- return (fd->id_asset_data_offs >= 0) ?
- *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offs) :
+ BLI_assert(blo_bhead_is_id_valid_type(bhead));
+ return (fd->id_asset_data_offset >= 0) ?
+ *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) :
NULL;
}
@@ -1054,9 +1073,9 @@ static bool read_file_dna(FileData *fd, const char **r_error_message)
fd->reconstruct_info = DNA_reconstruct_info_create(
fd->filesdna, fd->memsdna, fd->compflags);
/* used to retrieve ID names from (bhead+1) */
- fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]");
- BLI_assert(fd->id_name_offs != -1);
- fd->id_asset_data_offs = DNA_elem_offset(
+ fd->id_name_offset = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]");
+ BLI_assert(fd->id_name_offset != -1);
+ fd->id_asset_data_offset = DNA_elem_offset(
fd->filesdna, "ID", "AssetMetaData", "*asset_data");
return true;
@@ -1965,7 +1984,7 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
/* undo file support: add all library pointers in lookup */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
LISTBASE_FOREACH (Main *, ptr, old_mainlist) {
int i = set_listbasepointers(ptr, lbarray);
@@ -2424,7 +2443,9 @@ static void direct_link_id_common(
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
}
- BKE_lib_libblock_session_uuid_ensure(id);
+ if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_ensure(id);
+ }
id->lib = current_library;
id->us = ID_FAKE_USERS(id);
@@ -2983,6 +3004,12 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
sclip->scopes.ok = 0;
}
+ else if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+
+ sspreadsheet->pinned_id = restore_pointer_by_name(
+ id_map, sspreadsheet->pinned_id, USER_IGNORE);
+ }
}
}
}
@@ -3168,7 +3195,9 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn
BLI_addtail(lb, ph_id);
id_sort_by_name(lb, ph_id, NULL);
- BKE_lib_libblock_session_uuid_ensure(ph_id);
+ if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_ensure(ph_id);
+ }
return ph_id;
}
@@ -3701,7 +3730,7 @@ static BHead *read_libblock(FileData *fd,
BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
{
- BLI_assert(BKE_idtype_idcode_is_valid(bhead->code));
+ BLI_assert(blo_bhead_is_id_valid_type(bhead));
bhead = read_data_into_datamap(fd, bhead, "asset-data read");
@@ -3741,7 +3770,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
* (not after loading file). */
if (bfd->filename[0] == 0) {
if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) {
- if ((G.fileflags & G_FILE_RECOVER) == 0) {
+ if ((G.fileflags & G_FILE_RECOVER_READ) == 0) {
BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
}
}
@@ -3752,7 +3781,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
}
}
- if (G.fileflags & G_FILE_RECOVER) {
+ if (G.fileflags & G_FILE_RECOVER_READ) {
BLI_strncpy(fd->relabase, fg->filename, sizeof(fd->relabase));
}
@@ -4208,6 +4237,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* we can re-generate overrides from their references. */
if (fd->memfile == NULL) {
/* Do not apply in undo case! */
+ BKE_lib_override_library_main_validate(bfd->main, fd->reports);
BKE_lib_override_library_main_update(bfd->main);
}
@@ -4411,7 +4441,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
if (id == NULL) {
/* ID has not been read yet, add placeholder to the main of the
* library it belongs to, so that it will be read later. */
- read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL);
+ read_libblock(fd, libmain, bhead, fd->id_tag_extra | LIB_TAG_INDIRECT, false, NULL);
/* commented because this can print way too much */
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath);
@@ -4466,7 +4496,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
ID *id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
- read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL);
+ read_libblock(fd,
+ mainvar,
+ bhead,
+ fd->id_tag_extra | LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT,
+ false,
+ NULL);
}
else {
/* Convert any previously read weak link to regular link
@@ -4543,7 +4578,7 @@ void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
*/
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
FileData *fd = fdhandle;
ID *id;
int a;
@@ -4713,7 +4748,7 @@ static void add_loose_object_data_to_scene(Main *mainvar,
}
/* Loop over all ID types, instancing object-data for ID types that have support for it. */
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int i = set_listbasepointers(mainvar, lbarray);
while (i--) {
const short idcode = BKE_idtype_idcode_from_index(i);
@@ -4847,7 +4882,7 @@ static ID *link_named_part(
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
/* not read yet */
- const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN;
+ const int tag = ((force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN) | fd->id_tag_extra);
read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id);
if (id) {
@@ -4908,7 +4943,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_t
break;
}
- if (BKE_idtype_idcode_is_valid(bhead->code) && BKE_idtype_idcode_is_linkable(bhead->code) &&
+ if (blo_bhead_is_id_valid_type(bhead) && BKE_idtype_idcode_is_linkable((short)bhead->code) &&
(id_types_mask == 0 ||
(BKE_idtype_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id);
@@ -4979,7 +5014,7 @@ static bool library_link_idcode_needs_tag_check(const short idcode, const int fl
*/
static void library_link_clear_tag(Main *mainvar, const int flag)
{
- for (int i = 0; i < MAX_LIBARRAY; i++) {
+ for (int i = 0; i < INDEX_ID_MAX; i++) {
const short idcode = BKE_idtype_idcode_from_index(i);
BLI_assert(idcode != -1);
if (library_link_idcode_needs_tag_check(idcode, flag)) {
@@ -4988,10 +5023,18 @@ static void library_link_clear_tag(Main *mainvar, const int flag)
}
}
-static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath, const int flag)
+static Main *library_link_begin(
+ Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra)
{
Main *mainl;
+ /* Only allow specific tags to be set as extra,
+ * otherwise this could conflict with library loading logic.
+ * Other flags can be added here, as long as they are safe. */
+ BLI_assert((id_tag_extra & ~LIB_TAG_TEMP_MAIN) == 0);
+
+ (*fd)->id_tag_extra = id_tag_extra;
+
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
@@ -5017,22 +5060,25 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag)
+ const int flag,
+ const int id_tag_extra)
{
memset(params, 0, sizeof(*params));
params->bmain = bmain;
params->flag = flag;
+ params->id_tag_extra = id_tag_extra;
}
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
struct Main *bmain,
const int flag,
+ const int id_tag_extra,
/* Context arguments. */
struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d)
{
- BLO_library_link_params_init(params, bmain, flag);
+ BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
if (scene != NULL) {
/* Tagging is needed for instancing. */
params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
@@ -5057,7 +5103,7 @@ Main *BLO_library_link_begin(BlendHandle **bh,
const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return library_link_begin(params->bmain, &fd, filepath, params->flag);
+ return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
@@ -5068,8 +5114,8 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
main_newid->curlib = mainptr->curlib;
- ListBase *lbarray[MAX_LIBARRAY];
- ListBase *lbarray_newid[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
+ ListBase *lbarray_newid[INDEX_ID_MAX];
int i = set_listbasepointers(mainptr, lbarray);
set_listbasepointers(main_newid, lbarray_newid);
while (i--) {
@@ -5227,7 +5273,7 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
static int has_linked_ids_to_read(Main *mainvar)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {
@@ -5295,7 +5341,7 @@ static void read_library_linked_ids(FileData *basefd,
{
GHash *loaded_ids = BLI_ghash_str_new(__func__);
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {
@@ -5344,7 +5390,7 @@ static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist,
{
/* Any remaining weak links at this point have been lost, silently drop
* those by setting them to NULL pointers. */
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index b81d8bd9a2b..9682b5456d2 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -110,16 +110,24 @@ typedef struct FileData {
int fileversion;
/** Used to retrieve ID names from (bhead+1). */
- int id_name_offs;
+ int id_name_offset;
/** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files,
* will be -1 then! */
- int id_asset_data_offs;
+ int id_asset_data_offset;
/** For do_versions patching. */
int globalf, fileflags;
/** Optionally skip some data-blocks when they're not needed. */
eBLOReadSkip skip_flags;
+ /**
+ * Tag to apply to all loaded ID data-blocks.
+ *
+ * \note This is initialized from #LibraryLink_Params.id_tag_extra since passing it as an
+ * argument would need an additional argument to be passed around when expanding library data.
+ */
+ int id_tag_extra;
+
struct OldNewMap *datamap;
struct OldNewMap *globmap;
struct OldNewMap *libmap;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 983fdce15f1..467fd8b0399 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -449,7 +449,9 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name)
BKE_id_new_name_validate(lb, id, name);
/* alphabetic insertion: is in BKE_id_new_name_validate */
- BKE_lib_libblock_session_uuid_ensure(id);
+ if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_ensure(id);
+ }
if (G.debug & G_DEBUG) {
printf("Converted GPencil to ID: %s\n", id->name + 2);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index d86ddc5b646..289092f7f19 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1141,7 +1141,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 276, 5)) {
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a;
/* Important to clear all non-persistent flags from older versions here,
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index ef2e196094e..1ecaee10e6a 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3684,7 +3684,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
/* Those are not currently used, but are accessible through RNA API and were not
- * properly initialized previously. This is mere copy of BKE_init_scene() code. */
+ * properly initialized previously. This is mere copy of #scene_init_data code. */
if (scene->r.im_format.view_settings.look[0] == '\0') {
BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings);
BKE_color_managed_view_settings_init_render(
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index fa9f00d67ec..bf70a50631f 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -62,6 +62,7 @@
#include "BKE_multires.h"
#include "BKE_node.h"
+#include "IMB_imbuf.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -101,6 +102,15 @@ static eSpaceSeq_Proxy_RenderSize get_sequencer_render_size(Main *bmain)
return render_size;
}
+static bool can_use_proxy(Sequence *seq, int psize)
+{
+ if (seq->strip->proxy == NULL) {
+ return false;
+ }
+ short size_flags = seq->strip->proxy->build_size_flags;
+ return (seq->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE && (size_flags & psize) != 0;
+}
+
/* image_size is width or height depending what RNA property is converted - X or Y. */
static void seq_convert_transform_animation(const Scene *scene,
const char *path,
@@ -149,7 +159,7 @@ static void seq_convert_transform_crop(const Scene *scene,
image_size_x = s_elem->orig_width;
image_size_y = s_elem->orig_height;
- if (SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) {
+ if (can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) {
image_size_x /= SEQ_rendersize_to_scale_factor(render_size);
image_size_y /= SEQ_rendersize_to_scale_factor(render_size);
}
@@ -282,7 +292,7 @@ static void seq_convert_transform_crop_2(const Scene *scene,
int image_size_x = s_elem->orig_width;
int image_size_y = s_elem->orig_height;
- if (SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) {
+ if (can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) {
image_size_x /= SEQ_rendersize_to_scale_factor(render_size);
image_size_y /= SEQ_rendersize_to_scale_factor(render_size);
}
@@ -796,6 +806,26 @@ static void version_node_join_geometry_for_multi_input_socket(bNodeTree *ntree)
}
}
+static ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
+ int region_type,
+ const char *name,
+ int link_after_region_type)
+{
+ ARegion *link_after_region = NULL;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == region_type) {
+ return NULL;
+ }
+ if (region->regiontype == link_after_region_type) {
+ link_after_region = region;
+ }
+ }
+ ARegion *new_region = MEM_callocN(sizeof(ARegion), name);
+ new_region->regiontype = region_type;
+ BLI_insertlinkafter(regionbase, link_after_region, new_region);
+ return new_region;
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -1462,14 +1492,13 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->nodetree) {
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
- if (node->type == CMP_NODE_CRYPTOMATTE) {
+ if (node->type == CMP_NODE_CRYPTOMATTE_LEGACY) {
NodeCryptomatte *storage = (NodeCryptomatte *)node->storage;
char *matte_id = storage->matte_id;
if (matte_id == NULL || strlen(storage->matte_id) == 0) {
continue;
}
BKE_cryptomatte_matte_id_to_entries(storage, storage->matte_id);
- MEM_SAFE_FREE(storage->matte_id);
}
}
}
@@ -1789,6 +1818,92 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_END;
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 10)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_socket_name(ntree, GEO_NODE_ATTRIBUTE_PROXIMITY, "Location", "Position");
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ /* Fix old scene with too many samples that were not being used.
+ * Now they are properly used and might produce a huge slowdown.
+ * So we clamp to what the old max actual was. */
+ if (scene->eevee.volumetric_shadow_samples > 32) {
+ scene->eevee.volumetric_shadow_samples = 32;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 11)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (STREQ(node->idname, "GeometryNodeSubdivisionSurfaceSimple")) {
+ STRNCPY(node->idname, "GeometryNodeSubdivide");
+ }
+ if (STREQ(node->idname, "GeometryNodeSubdivisionSurface")) {
+ STRNCPY(node->idname, "GeometryNodeSubdivideSmooth");
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 12)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ if (ELEM(sseq->render_size,
+ SEQ_RENDER_SIZE_PROXY_100,
+ SEQ_RENDER_SIZE_PROXY_75,
+ SEQ_RENDER_SIZE_PROXY_50,
+ SEQ_RENDER_SIZE_PROXY_25)) {
+ sseq->flag |= SEQ_USE_PROXIES;
+ }
+ if (sseq->render_size == SEQ_RENDER_SIZE_FULL) {
+ sseq->render_size = SEQ_RENDER_SIZE_PROXY_100;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *new_footer = do_versions_add_region_if_not_found(
+ regionbase, RGN_TYPE_FOOTER, "footer for spreadsheet", RGN_TYPE_HEADER);
+ if (new_footer != NULL) {
+ new_footer->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP :
+ RGN_ALIGN_BOTTOM;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 13)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (STREQ(node->idname, "GeometryNodeSubdivideSmooth")) {
+ STRNCPY(node->idname, "GeometryNodeSubdivisionSurface");
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -1800,12 +1915,5 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
-
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_ATTRIBUTE_PROXIMITY, "Location", "Position");
- }
- }
- FOREACH_NODETREE_END;
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 52efeb1e822..10b24532014 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -184,6 +184,9 @@ static void blo_update_defaults_screen(bScreen *screen,
SpaceSeq *seq = area->spacedata.first;
seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY |
SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_DURATION;
+
+ seq->render_size = SEQ_RENDER_SIZE_PROXY_100;
+ seq->flag |= SEQ_USE_PROXIES;
}
else if (area->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 3d39181cd32..8cbedb05931 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -282,6 +282,8 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_info.info_property);
FROM_DEFAULT_V4_UCHAR(space_info.info_error);
FROM_DEFAULT_V4_UCHAR(space_info.info_operator);
+
+ btheme->space_spreadsheet = btheme->space_outliner;
}
#undef FROM_DEFAULT_V4_UCHAR
@@ -843,6 +845,14 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->experimental.use_asset_browser = true;
}
+ if (!USER_VERSION_ATLEAST(293, 12)) {
+ if (userdef->gizmo_size_navigate_v3d == 0) {
+ userdef->gizmo_size_navigate_v3d = 80;
+ }
+
+ userdef->sequencer_proxy_setup = USER_SEQ_PROXY_SETUP_AUTOMATIC;
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -854,9 +864,6 @@ void blo_do_versions_userdef(UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
- if (userdef->gizmo_size_navigate_v3d == 0) {
- userdef->gizmo_size_navigate_v3d = 80;
- }
}
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0a4f2fde93f..4ac49d5aebb 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -768,7 +768,7 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef)
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
ID *id;
int a, tot;
bool found_one;
@@ -870,7 +870,10 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.fileflags = (fileflags & ~G_FILE_FLAG_ALL_RUNTIME);
fg.globalf = G.f;
- BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
+ /* Write information needed for recovery. */
+ if (fileflags & G_FILE_RECOVER_WRITE) {
+ BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
+ }
sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
@@ -954,7 +957,7 @@ static bool write_file_handle(Main *mainvar,
* if needed, without duplicating whole code. */
Main *bmain = mainvar;
do {
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(bmain, lbarray);
while (a--) {
ID *id = lbarray[a]->first;
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 9cd1a2fd4ec..d479a555a58 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -46,7 +46,7 @@ static void recount_totsels(BMesh *bm)
int *tots[3];
int i;
- /* recount (tot * sel) variables */
+ /* Recount total selection variables. */
bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
tots[0] = &bm->totvertsel;
tots[1] = &bm->totedgesel;
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index 22ee8809a19..ce0f8ae8324 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -114,6 +114,7 @@ enum {
BMW_FACELOOP,
BMW_EDGERING,
BMW_EDGEBOUNDARY,
+ BMW_EDGELOOP_NONMANIFOLD,
/* BMW_RING, */
BMW_LOOPDATA_ISLAND,
BMW_ISLANDBOUND,
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 647a22baaeb..a8558ec4011 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -1596,6 +1596,118 @@ static void *bmw_UVEdgeWalker_step(BMWalker *walker)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Non-manifold Edge Walker
+ * \{ */
+
+static void bmw_NonManifoldedgeWalker_begin(BMWalker *walker, void *data)
+{
+ BMwNonManifoldEdgeLoopWalker *lwalk;
+ BMEdge *e = data;
+
+ if (BLI_gset_haskey(walker->visit_set, e)) {
+ return;
+ }
+
+ lwalk = BMW_state_add(walker);
+ lwalk->start = e;
+ lwalk->cur = e;
+ lwalk->startv = e->v1;
+ lwalk->lastv = e->v1;
+ lwalk->face_count = BM_edge_face_count(e);
+ BLI_gset_insert(walker->visit_set, e);
+}
+
+static void *bmw_NonManifoldedgeWalker_yield(BMWalker *walker)
+{
+ BMwNonManifoldEdgeLoopWalker *lwalk = BMW_current_state(walker);
+
+ if (!lwalk) {
+ return NULL;
+ }
+ return lwalk->cur;
+}
+
+/**
+ * Walk over manifold loops around `v` until loop-edge is found with `face_count` users.
+ * or return NULL if not found.
+ * */
+static BMLoop *bmw_NonManifoldLoop_find_next_around_vertex(BMLoop *l, BMVert *v, int face_count)
+{
+ BLI_assert(!BM_loop_is_manifold(l));
+ do {
+ l = BM_loop_other_edge_loop(l, v);
+ if (BM_loop_is_manifold(l)) {
+ l = l->radial_next;
+ }
+ else if (BM_edge_face_count_is_equal(l->e, face_count)) {
+ return l;
+ }
+ else {
+ break;
+ }
+ } while (true);
+ return NULL;
+}
+
+static void *bmw_NonManifoldedgeWalker_step(BMWalker *walker)
+{
+ BMwNonManifoldEdgeLoopWalker *lwalk, owalk;
+ BMW_state_remove_r(walker, &owalk);
+ lwalk = &owalk;
+ BMLoop *l_cur = NULL;
+ const int face_count = lwalk->face_count;
+
+ BMVert *v = NULL;
+
+ /* Use the second pass is unlikely, only needed to walk back in the opposite direction. */
+ for (int pass = 0; pass < 2; pass++) {
+
+ BMEdge *e = lwalk->cur;
+ v = BM_edge_other_vert(e, lwalk->lastv);
+
+ /* If `lwalk.lastv` can't be walked along, start walking in the opposite direction
+ * on the initial edge, do this at most one time during this walk operation. */
+ if (UNLIKELY(pass == 1)) {
+ e = lwalk->start;
+ v = lwalk->startv;
+ }
+
+ BMLoop *l = e->l;
+ do {
+ BMLoop *l_next = bmw_NonManifoldLoop_find_next_around_vertex(l, v, face_count);
+ if ((l_next != NULL) && !BLI_gset_haskey(walker->visit_set, l_next->e)) {
+ if (l_cur == NULL) {
+ l_cur = l_next;
+ }
+ else if (l_cur->e != l_next->e) {
+ /* If there are more than one possible edge to step onto (unlikely but possible),
+ * treat as a junction and stop walking as there is no correct answer in this case. */
+ l_cur = NULL;
+ break;
+ }
+ }
+ } while ((l = l->radial_next) != e->l);
+
+ if (l_cur != NULL) {
+ break;
+ }
+ }
+
+ if (l_cur != NULL) {
+ BLI_assert(!BLI_gset_haskey(walker->visit_set, l_cur->e));
+ BLI_assert(BM_edge_face_count(l_cur->e) == face_count);
+ lwalk = BMW_state_add(walker);
+ lwalk->lastv = v;
+ lwalk->cur = l_cur->e;
+ lwalk->face_count = face_count;
+ BLI_gset_insert(walker->visit_set, l_cur->e);
+ }
+ return owalk.cur;
+}
+
+/** \} */
+
static BMWalker bmw_VertShellWalker_Type = {
BM_VERT | BM_EDGE,
bmw_VertShellWalker_begin,
@@ -1708,6 +1820,16 @@ static BMWalker bmw_EdgeboundaryWalker_Type = {
0,
};
+static BMWalker bmw_NonManifoldedgeWalker_type = {
+ BM_EDGE,
+ bmw_NonManifoldedgeWalker_begin,
+ bmw_NonManifoldedgeWalker_step,
+ bmw_NonManifoldedgeWalker_yield,
+ sizeof(BMwNonManifoldEdgeLoopWalker),
+ BMW_DEPTH_FIRST,
+ 0,
+};
+
static BMWalker bmw_UVEdgeWalker_Type = {
BM_LOOP,
bmw_UVEdgeWalker_begin,
@@ -1737,6 +1859,7 @@ BMWalker *bm_walker_types[] = {
&bmw_FaceLoopWalker_Type, /* #BMW_FACELOOP */
&bmw_EdgeringWalker_Type, /* #BMW_EDGERING */
&bmw_EdgeboundaryWalker_Type, /* #BMW_EDGEBOUNDARY */
+ &bmw_NonManifoldedgeWalker_type, /* #BMW_EDGELOOP_NONMANIFOLD */
&bmw_UVEdgeWalker_Type, /* #BMW_LOOPDATA_ISLAND */
&bmw_IslandboundWalker_Type, /* #BMW_ISLANDBOUND */
&bmw_IslandWalker_Type, /* #BMW_ISLAND */
diff --git a/source/blender/bmesh/intern/bmesh_walkers_private.h b/source/blender/bmesh/intern/bmesh_walkers_private.h
index 721f3c2c65b..2da4f290c76 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_private.h
+++ b/source/blender/bmesh/intern/bmesh_walkers_private.h
@@ -84,6 +84,13 @@ typedef struct BMwEdgeboundaryWalker {
BMEdge *e;
} BMwEdgeboundaryWalker;
+typedef struct BMwNonManifoldEdgeLoopWalker {
+ BMwGenericWalker header;
+ BMEdge *start, *cur;
+ BMVert *startv, *lastv;
+ int face_count; /* face count around the edge. */
+} BMwNonManifoldEdgeLoopWalker;
+
typedef struct BMwUVEdgeWalker {
BMwGenericWalker header;
BMLoop *l;
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 535df52c1e1..a0a31ab6154 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -728,10 +728,10 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out");
const float dia = BMO_slot_float_get(op->slots_in, "size");
- const uint xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments"));
- const uint ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments"));
- const float xtot_inv2 = 2.0f / (xtot - 1);
- const float ytot_inv2 = 2.0f / (ytot - 1);
+ const uint xtot = max_ii(1, BMO_slot_int_get(op->slots_in, "x_segments"));
+ const uint ytot = max_ii(1, BMO_slot_int_get(op->slots_in, "y_segments"));
+ const float xtot_inv2 = 2.0f / (xtot);
+ const float ytot_inv2 = 2.0f / (ytot);
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
@@ -746,14 +746,14 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
- BMO_slot_buffer_alloc(op, op->slots_out, "verts.out", xtot * ytot);
+ BMO_slot_buffer_alloc(op, op->slots_out, "verts.out", (xtot + 1) * (ytot + 1));
varr = (BMVert **)slot_verts_out->data.buf;
i = 0;
vec[2] = 0.0f;
- for (y = 0; y < ytot; y++) {
+ for (y = 0; y <= ytot; y++) {
vec[1] = ((y * ytot_inv2) - 1.0f) * dia;
- for (x = 0; x < xtot; x++) {
+ for (x = 0; x <= xtot; x++) {
vec[0] = ((x * xtot_inv2) - 1.0f) * dia;
mul_v3_m4v3(tvec, mat, vec);
varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
@@ -762,10 +762,10 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
}
}
-#define XY(_x, _y) ((_x) + ((_y) * (xtot)))
+#define XY(_x, _y) ((_x) + ((_y) * (xtot + 1)))
- for (y = 1; y < ytot; y++) {
- for (x = 1; x < xtot; x++) {
+ for (y = 1; y <= ytot; y++) {
+ for (x = 1; x <= xtot; x++) {
BMFace *f;
vquad[0] = varr[XY(x - 1, y - 1)];
@@ -805,8 +805,8 @@ void BM_mesh_calc_uvs_grid(BMesh *bm,
BMLoop *l;
BMIter iter, liter;
- const float dx = 1.0f / (float)(x_segments - 1);
- const float dy = 1.0f / (float)(y_segments - 1);
+ const float dx = 1.0f / (float)(x_segments);
+ const float dy = 1.0f / (float)(y_segments);
const float dx_wrap = 1.0 - (dx / 2.0f);
float x = 0.0f;
float y = dy;
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index ea5d66e195c..fec33a04e6f 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -354,6 +354,7 @@ static bool bmesh_boolean(BMesh *bm,
const bool use_self,
const bool use_separate_all,
const bool keep_hidden,
+ const bool hole_tolerant,
const BoolOpType boolean_mode)
{
IMeshArena arena;
@@ -389,7 +390,7 @@ static bool bmesh_boolean(BMesh *bm,
};
}
IMesh m_out = boolean_mesh(
- m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena);
+ m_in, boolean_mode, nshapes, shape_fn, use_self, hole_tolerant, &m_triangulated, &arena);
# ifdef PERF_DEBUG
double boolean_time = PIL_check_seconds_timer();
std::cout << "boolean done, time = " << boolean_time - mesh_time << "\n";
@@ -437,6 +438,7 @@ bool BM_mesh_boolean(BMesh *bm,
const int nshapes,
const bool use_self,
const bool keep_hidden,
+ const bool hole_tolerant,
const int boolean_mode)
{
return blender::meshintersect::bmesh_boolean(
@@ -449,6 +451,7 @@ bool BM_mesh_boolean(BMesh *bm,
use_self,
false,
keep_hidden,
+ hole_tolerant,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
@@ -468,6 +471,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
const int nshapes,
const bool use_self,
const bool use_separate_all,
+ const bool hole_tolerant,
const bool keep_hidden)
{
return blender::meshintersect::bmesh_boolean(bm,
@@ -479,6 +483,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
use_self,
use_separate_all,
keep_hidden,
+ hole_tolerant,
blender::meshintersect::BoolOpType::None);
}
#else
@@ -490,6 +495,7 @@ bool BM_mesh_boolean(BMesh *UNUSED(bm),
const int UNUSED(nshapes),
const bool UNUSED(use_self),
const bool UNUSED(keep_hidden),
+ const bool UNUSED(hole_tolerant),
const int UNUSED(boolean_mode))
{
UNUSED_VARS(looptris, test_fn);
@@ -512,6 +518,7 @@ bool BM_mesh_boolean_knife(BMesh *UNUSED(bm),
const int UNUSED(nshapes),
const bool UNUSED(use_self),
const bool UNUSED(use_separate_all),
+ const bool UNUSED(hole_tolerant),
const bool UNUSED(keep_hidden))
{
UNUSED_VARS(looptris, test_fn);
diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h
index 2cc32e143fc..ed77242e14c 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.h
+++ b/source/blender/bmesh/tools/bmesh_boolean.h
@@ -32,6 +32,7 @@ bool BM_mesh_boolean(BMesh *bm,
const int nshapes,
const bool use_self,
const bool keep_hidden,
+ const bool hole_tolerant,
const int boolean_mode);
bool BM_mesh_boolean_knife(BMesh *bm,
@@ -42,6 +43,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
const int nshapes,
const bool use_self,
const bool use_separate_all,
+ const bool hole_tolerant,
const bool keep_hidden);
#ifdef __cplusplus
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index a226b009ec9..64033cbe5c4 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -49,504 +49,504 @@ set(SRC
COM_compositor.h
COM_defines.h
- intern/COM_CPUDevice.cpp
+ intern/COM_CPUDevice.cc
intern/COM_CPUDevice.h
- intern/COM_ChunkOrder.cpp
+ intern/COM_ChunkOrder.cc
intern/COM_ChunkOrder.h
- intern/COM_ChunkOrderHotspot.cpp
+ intern/COM_ChunkOrderHotspot.cc
intern/COM_ChunkOrderHotspot.h
- intern/COM_CompositorContext.cpp
+ intern/COM_CompositorContext.cc
intern/COM_CompositorContext.h
- intern/COM_Converter.cpp
+ intern/COM_Converter.cc
intern/COM_Converter.h
- intern/COM_Debug.cpp
+ intern/COM_Debug.cc
intern/COM_Debug.h
- intern/COM_Device.cpp
+ intern/COM_Device.cc
intern/COM_Device.h
- intern/COM_ExecutionGroup.cpp
+ intern/COM_ExecutionGroup.cc
intern/COM_ExecutionGroup.h
- intern/COM_ExecutionSystem.cpp
+ intern/COM_ExecutionSystem.cc
intern/COM_ExecutionSystem.h
- intern/COM_MemoryBuffer.cpp
+ intern/COM_MemoryBuffer.cc
intern/COM_MemoryBuffer.h
- intern/COM_MemoryProxy.cpp
+ intern/COM_MemoryProxy.cc
intern/COM_MemoryProxy.h
- intern/COM_MetaData.cpp
+ intern/COM_MetaData.cc
intern/COM_MetaData.h
- intern/COM_Node.cpp
+ intern/COM_Node.cc
intern/COM_Node.h
- intern/COM_NodeConverter.cpp
+ intern/COM_NodeConverter.cc
intern/COM_NodeConverter.h
- intern/COM_NodeGraph.cpp
+ intern/COM_NodeGraph.cc
intern/COM_NodeGraph.h
- intern/COM_NodeOperation.cpp
+ intern/COM_NodeOperation.cc
intern/COM_NodeOperation.h
- intern/COM_NodeOperationBuilder.cpp
+ intern/COM_NodeOperationBuilder.cc
intern/COM_NodeOperationBuilder.h
- intern/COM_OpenCLDevice.cpp
+ intern/COM_OpenCLDevice.cc
intern/COM_OpenCLDevice.h
- intern/COM_SingleThreadedOperation.cpp
+ intern/COM_SingleThreadedOperation.cc
intern/COM_SingleThreadedOperation.h
- intern/COM_SocketReader.cpp
+ intern/COM_SocketReader.cc
intern/COM_SocketReader.h
- intern/COM_WorkPackage.cpp
+ intern/COM_WorkPackage.cc
intern/COM_WorkPackage.h
- intern/COM_WorkScheduler.cpp
+ intern/COM_WorkScheduler.cc
intern/COM_WorkScheduler.h
- intern/COM_compositor.cpp
+ intern/COM_compositor.cc
- operations/COM_QualityStepHelper.cpp
+ operations/COM_QualityStepHelper.cc
operations/COM_QualityStepHelper.h
# Internal nodes
- nodes/COM_SocketProxyNode.cpp
+ nodes/COM_SocketProxyNode.cc
nodes/COM_SocketProxyNode.h
# input nodes
- nodes/COM_BokehImageNode.cpp
+ nodes/COM_BokehImageNode.cc
nodes/COM_BokehImageNode.h
- nodes/COM_ColorNode.cpp
+ nodes/COM_ColorNode.cc
nodes/COM_ColorNode.h
- nodes/COM_ImageNode.cpp
+ nodes/COM_ImageNode.cc
nodes/COM_ImageNode.h
- nodes/COM_MaskNode.cpp
+ nodes/COM_MaskNode.cc
nodes/COM_MaskNode.h
- nodes/COM_MovieClipNode.cpp
+ nodes/COM_MovieClipNode.cc
nodes/COM_MovieClipNode.h
- nodes/COM_OutputFileNode.cpp
+ nodes/COM_OutputFileNode.cc
nodes/COM_OutputFileNode.h
- nodes/COM_RenderLayersNode.cpp
+ nodes/COM_RenderLayersNode.cc
nodes/COM_RenderLayersNode.h
- nodes/COM_SwitchNode.cpp
+ nodes/COM_SwitchNode.cc
nodes/COM_SwitchNode.h
- nodes/COM_SwitchViewNode.cpp
+ nodes/COM_SwitchViewNode.cc
nodes/COM_SwitchViewNode.h
- nodes/COM_TextureNode.cpp
+ nodes/COM_TextureNode.cc
nodes/COM_TextureNode.h
- nodes/COM_TimeNode.cpp
+ nodes/COM_TimeNode.cc
nodes/COM_TimeNode.h
- nodes/COM_ValueNode.cpp
+ nodes/COM_ValueNode.cc
nodes/COM_ValueNode.h
# output nodes
- nodes/COM_CompositorNode.cpp
+ nodes/COM_CompositorNode.cc
nodes/COM_CompositorNode.h
- nodes/COM_SplitViewerNode.cpp
+ nodes/COM_SplitViewerNode.cc
nodes/COM_SplitViewerNode.h
- nodes/COM_ViewLevelsNode.cpp
+ nodes/COM_ViewLevelsNode.cc
nodes/COM_ViewLevelsNode.h
- nodes/COM_ViewerNode.cpp
+ nodes/COM_ViewerNode.cc
nodes/COM_ViewerNode.h
- operations/COM_CalculateMeanOperation.cpp
+ operations/COM_CalculateMeanOperation.cc
operations/COM_CalculateMeanOperation.h
- operations/COM_CalculateStandardDeviationOperation.cpp
+ operations/COM_CalculateStandardDeviationOperation.cc
operations/COM_CalculateStandardDeviationOperation.h
# distort nodes
- nodes/COM_FlipNode.cpp
+ nodes/COM_FlipNode.cc
nodes/COM_FlipNode.h
- nodes/COM_RotateNode.cpp
+ nodes/COM_RotateNode.cc
nodes/COM_RotateNode.h
- nodes/COM_ScaleNode.cpp
+ nodes/COM_ScaleNode.cc
nodes/COM_ScaleNode.h
- nodes/COM_TranslateNode.cpp
+ nodes/COM_TranslateNode.cc
nodes/COM_TranslateNode.h
- nodes/COM_DisplaceNode.cpp
+ nodes/COM_DisplaceNode.cc
nodes/COM_DisplaceNode.h
- nodes/COM_MapUVNode.cpp
+ nodes/COM_MapUVNode.cc
nodes/COM_MapUVNode.h
- nodes/COM_ChannelMatteNode.cpp
+ nodes/COM_ChannelMatteNode.cc
nodes/COM_ChannelMatteNode.h
- nodes/COM_ChromaMatteNode.cpp
+ nodes/COM_ChromaMatteNode.cc
nodes/COM_ChromaMatteNode.h
- nodes/COM_ColorMatteNode.cpp
+ nodes/COM_ColorMatteNode.cc
nodes/COM_ColorMatteNode.h
- nodes/COM_DifferenceMatteNode.cpp
+ nodes/COM_DifferenceMatteNode.cc
nodes/COM_DifferenceMatteNode.h
- nodes/COM_DistanceMatteNode.cpp
+ nodes/COM_DistanceMatteNode.cc
nodes/COM_DistanceMatteNode.h
- nodes/COM_LensDistortionNode.cpp
+ nodes/COM_LensDistortionNode.cc
nodes/COM_LensDistortionNode.h
- nodes/COM_LuminanceMatteNode.cpp
+ nodes/COM_LuminanceMatteNode.cc
nodes/COM_LuminanceMatteNode.h
- nodes/COM_GlareNode.cpp
+ nodes/COM_GlareNode.cc
nodes/COM_GlareNode.h
- nodes/COM_SunBeamsNode.cpp
+ nodes/COM_SunBeamsNode.cc
nodes/COM_SunBeamsNode.h
- operations/COM_SunBeamsOperation.cpp
+ operations/COM_SunBeamsOperation.cc
operations/COM_SunBeamsOperation.h
- nodes/COM_CryptomatteNode.cpp
+ nodes/COM_CryptomatteNode.cc
nodes/COM_CryptomatteNode.h
- operations/COM_CryptomatteOperation.cpp
+ operations/COM_CryptomatteOperation.cc
operations/COM_CryptomatteOperation.h
- nodes/COM_CornerPinNode.cpp
+ nodes/COM_CornerPinNode.cc
nodes/COM_CornerPinNode.h
- nodes/COM_PlaneTrackDeformNode.cpp
+ nodes/COM_PlaneTrackDeformNode.cc
nodes/COM_PlaneTrackDeformNode.h
- nodes/COM_CropNode.cpp
+ nodes/COM_CropNode.cc
nodes/COM_CropNode.h
- operations/COM_CropOperation.cpp
+ operations/COM_CropOperation.cc
operations/COM_CropOperation.h
- nodes/COM_DefocusNode.cpp
+ nodes/COM_DefocusNode.cc
nodes/COM_DefocusNode.h
- nodes/COM_MovieDistortionNode.cpp
+ nodes/COM_MovieDistortionNode.cc
nodes/COM_MovieDistortionNode.h
- nodes/COM_Stabilize2dNode.cpp
+ nodes/COM_Stabilize2dNode.cc
nodes/COM_Stabilize2dNode.h
- nodes/COM_TransformNode.cpp
+ nodes/COM_TransformNode.cc
nodes/COM_TransformNode.h
# color nodes
- nodes/COM_AlphaOverNode.cpp
+ nodes/COM_AlphaOverNode.cc
nodes/COM_AlphaOverNode.h
- nodes/COM_BrightnessNode.cpp
+ nodes/COM_BrightnessNode.cc
nodes/COM_BrightnessNode.h
- nodes/COM_ColorBalanceNode.cpp
+ nodes/COM_ColorBalanceNode.cc
nodes/COM_ColorBalanceNode.h
- nodes/COM_ColorCorrectionNode.cpp
+ nodes/COM_ColorCorrectionNode.cc
nodes/COM_ColorCorrectionNode.h
- nodes/COM_ColorCurveNode.cpp
+ nodes/COM_ColorCurveNode.cc
nodes/COM_ColorCurveNode.h
- nodes/COM_ColorExposureNode.cpp
+ nodes/COM_ColorExposureNode.cc
nodes/COM_ColorExposureNode.h
- nodes/COM_ColorRampNode.cpp
+ nodes/COM_ColorRampNode.cc
nodes/COM_ColorRampNode.h
- nodes/COM_ColorToBWNode.cpp
+ nodes/COM_ColorToBWNode.cc
nodes/COM_ColorToBWNode.h
- nodes/COM_ConvertAlphaNode.cpp
+ nodes/COM_ConvertAlphaNode.cc
nodes/COM_ConvertAlphaNode.h
- nodes/COM_GammaNode.cpp
+ nodes/COM_GammaNode.cc
nodes/COM_GammaNode.h
- nodes/COM_HueSaturationValueCorrectNode.cpp
+ nodes/COM_HueSaturationValueCorrectNode.cc
nodes/COM_HueSaturationValueCorrectNode.h
- nodes/COM_HueSaturationValueNode.cpp
+ nodes/COM_HueSaturationValueNode.cc
nodes/COM_HueSaturationValueNode.h
- nodes/COM_InvertNode.cpp
+ nodes/COM_InvertNode.cc
nodes/COM_InvertNode.h
- nodes/COM_MixNode.cpp
+ nodes/COM_MixNode.cc
nodes/COM_MixNode.h
- nodes/COM_SetAlphaNode.cpp
+ nodes/COM_SetAlphaNode.cc
nodes/COM_SetAlphaNode.h
- nodes/COM_TonemapNode.cpp
+ nodes/COM_TonemapNode.cc
nodes/COM_TonemapNode.h
- nodes/COM_VectorCurveNode.cpp
+ nodes/COM_VectorCurveNode.cc
nodes/COM_VectorCurveNode.h
- nodes/COM_ZCombineNode.cpp
+ nodes/COM_ZCombineNode.cc
nodes/COM_ZCombineNode.h
- operations/COM_TonemapOperation.cpp
+ operations/COM_TonemapOperation.cc
operations/COM_TonemapOperation.h
# converter nodes
- nodes/COM_CombineColorNode.cpp
+ nodes/COM_CombineColorNode.cc
nodes/COM_CombineColorNode.h
- nodes/COM_IDMaskNode.cpp
+ nodes/COM_IDMaskNode.cc
nodes/COM_IDMaskNode.h
- nodes/COM_SeparateColorNode.cpp
+ nodes/COM_SeparateColorNode.cc
nodes/COM_SeparateColorNode.h
- nodes/COM_MapRangeNode.cpp
+ nodes/COM_MapRangeNode.cc
nodes/COM_MapRangeNode.h
- nodes/COM_MapValueNode.cpp
+ nodes/COM_MapValueNode.cc
nodes/COM_MapValueNode.h
- nodes/COM_MathNode.cpp
+ nodes/COM_MathNode.cc
nodes/COM_MathNode.h
- nodes/COM_NormalNode.cpp
+ nodes/COM_NormalNode.cc
nodes/COM_NormalNode.h
- nodes/COM_NormalizeNode.cpp
+ nodes/COM_NormalizeNode.cc
nodes/COM_NormalizeNode.h
- operations/COM_NormalizeOperation.cpp
+ operations/COM_NormalizeOperation.cc
operations/COM_NormalizeOperation.h
- nodes/COM_PixelateNode.cpp
+ nodes/COM_PixelateNode.cc
nodes/COM_PixelateNode.h
- operations/COM_PixelateOperation.cpp
+ operations/COM_PixelateOperation.cc
operations/COM_PixelateOperation.h
# Filter nodes
- nodes/COM_BilateralBlurNode.cpp
+ nodes/COM_BilateralBlurNode.cc
nodes/COM_BilateralBlurNode.h
- operations/COM_BilateralBlurOperation.cpp
+ operations/COM_BilateralBlurOperation.cc
operations/COM_BilateralBlurOperation.h
- nodes/COM_VectorBlurNode.cpp
+ nodes/COM_VectorBlurNode.cc
nodes/COM_VectorBlurNode.h
- operations/COM_VectorBlurOperation.cpp
+ operations/COM_VectorBlurOperation.cc
operations/COM_VectorBlurOperation.h
- nodes/COM_BlurNode.cpp
+ nodes/COM_BlurNode.cc
nodes/COM_BlurNode.h
- nodes/COM_BokehBlurNode.cpp
+ nodes/COM_BokehBlurNode.cc
nodes/COM_BokehBlurNode.h
- nodes/COM_DenoiseNode.cpp
+ nodes/COM_DenoiseNode.cc
nodes/COM_DenoiseNode.h
- nodes/COM_DespeckleNode.cpp
+ nodes/COM_DespeckleNode.cc
nodes/COM_DespeckleNode.h
- nodes/COM_DilateErodeNode.cpp
+ nodes/COM_DilateErodeNode.cc
nodes/COM_DilateErodeNode.h
- nodes/COM_DirectionalBlurNode.cpp
+ nodes/COM_DirectionalBlurNode.cc
nodes/COM_DirectionalBlurNode.h
- nodes/COM_FilterNode.cpp
+ nodes/COM_FilterNode.cc
nodes/COM_FilterNode.h
- nodes/COM_InpaintNode.cpp
+ nodes/COM_InpaintNode.cc
nodes/COM_InpaintNode.h
- operations/COM_BlurBaseOperation.cpp
+ operations/COM_BlurBaseOperation.cc
operations/COM_BlurBaseOperation.h
- operations/COM_BokehBlurOperation.cpp
+ operations/COM_BokehBlurOperation.cc
operations/COM_BokehBlurOperation.h
- operations/COM_DirectionalBlurOperation.cpp
+ operations/COM_DirectionalBlurOperation.cc
operations/COM_DirectionalBlurOperation.h
- operations/COM_FastGaussianBlurOperation.cpp
+ operations/COM_FastGaussianBlurOperation.cc
operations/COM_FastGaussianBlurOperation.h
- operations/COM_GammaCorrectOperation.cpp
+ operations/COM_GammaCorrectOperation.cc
operations/COM_GammaCorrectOperation.h
- operations/COM_GaussianAlphaXBlurOperation.cpp
+ operations/COM_GaussianAlphaXBlurOperation.cc
operations/COM_GaussianAlphaXBlurOperation.h
- operations/COM_GaussianAlphaYBlurOperation.cpp
+ operations/COM_GaussianAlphaYBlurOperation.cc
operations/COM_GaussianAlphaYBlurOperation.h
- operations/COM_GaussianBokehBlurOperation.cpp
+ operations/COM_GaussianBokehBlurOperation.cc
operations/COM_GaussianBokehBlurOperation.h
- operations/COM_GaussianXBlurOperation.cpp
+ operations/COM_GaussianXBlurOperation.cc
operations/COM_GaussianXBlurOperation.h
- operations/COM_GaussianYBlurOperation.cpp
+ operations/COM_GaussianYBlurOperation.cc
operations/COM_GaussianYBlurOperation.h
- operations/COM_MovieClipAttributeOperation.cpp
+ operations/COM_MovieClipAttributeOperation.cc
operations/COM_MovieClipAttributeOperation.h
- operations/COM_MovieDistortionOperation.cpp
+ operations/COM_MovieDistortionOperation.cc
operations/COM_MovieDistortionOperation.h
- operations/COM_VariableSizeBokehBlurOperation.cpp
+ operations/COM_VariableSizeBokehBlurOperation.cc
operations/COM_VariableSizeBokehBlurOperation.h
# Matte nodes
- nodes/COM_BoxMaskNode.cpp
+ nodes/COM_BoxMaskNode.cc
nodes/COM_BoxMaskNode.h
- nodes/COM_ColorSpillNode.cpp
+ nodes/COM_ColorSpillNode.cc
nodes/COM_ColorSpillNode.h
- nodes/COM_DoubleEdgeMaskNode.cpp
+ nodes/COM_DoubleEdgeMaskNode.cc
nodes/COM_DoubleEdgeMaskNode.h
- nodes/COM_EllipseMaskNode.cpp
+ nodes/COM_EllipseMaskNode.cc
nodes/COM_EllipseMaskNode.h
- operations/COM_DoubleEdgeMaskOperation.cpp
+ operations/COM_DoubleEdgeMaskOperation.cc
operations/COM_DoubleEdgeMaskOperation.h
- nodes/COM_KeyingScreenNode.cpp
+ nodes/COM_KeyingScreenNode.cc
nodes/COM_KeyingScreenNode.h
- operations/COM_KeyingScreenOperation.cpp
+ operations/COM_KeyingScreenOperation.cc
operations/COM_KeyingScreenOperation.h
- nodes/COM_TrackPositionNode.cpp
+ nodes/COM_TrackPositionNode.cc
nodes/COM_TrackPositionNode.h
- operations/COM_TrackPositionOperation.cpp
+ operations/COM_TrackPositionOperation.cc
operations/COM_TrackPositionOperation.h
- nodes/COM_KeyingNode.cpp
+ nodes/COM_KeyingNode.cc
nodes/COM_KeyingNode.h
- operations/COM_KeyingBlurOperation.cpp
+ operations/COM_KeyingBlurOperation.cc
operations/COM_KeyingBlurOperation.h
- operations/COM_KeyingClipOperation.cpp
+ operations/COM_KeyingClipOperation.cc
operations/COM_KeyingClipOperation.h
- operations/COM_KeyingDespillOperation.cpp
+ operations/COM_KeyingDespillOperation.cc
operations/COM_KeyingDespillOperation.h
- operations/COM_KeyingOperation.cpp
+ operations/COM_KeyingOperation.cc
operations/COM_KeyingOperation.h
- operations/COM_ColorSpillOperation.cpp
+ operations/COM_ColorSpillOperation.cc
operations/COM_ColorSpillOperation.h
- operations/COM_RenderLayersProg.cpp
+ operations/COM_RenderLayersProg.cc
operations/COM_RenderLayersProg.h
- operations/COM_BokehImageOperation.cpp
+ operations/COM_BokehImageOperation.cc
operations/COM_BokehImageOperation.h
- operations/COM_ImageOperation.cpp
+ operations/COM_ImageOperation.cc
operations/COM_ImageOperation.h
- operations/COM_MultilayerImageOperation.cpp
+ operations/COM_MultilayerImageOperation.cc
operations/COM_MultilayerImageOperation.h
- operations/COM_TextureOperation.cpp
+ operations/COM_TextureOperation.cc
operations/COM_TextureOperation.h
- operations/COM_SocketProxyOperation.cpp
+ operations/COM_SocketProxyOperation.cc
operations/COM_SocketProxyOperation.h
- operations/COM_CompositorOperation.cpp
+ operations/COM_CompositorOperation.cc
operations/COM_CompositorOperation.h
- operations/COM_ConvertDepthToRadiusOperation.cpp
+ operations/COM_ConvertDepthToRadiusOperation.cc
operations/COM_ConvertDepthToRadiusOperation.h
- operations/COM_OutputFileMultiViewOperation.cpp
+ operations/COM_OutputFileMultiViewOperation.cc
operations/COM_OutputFileMultiViewOperation.h
- operations/COM_OutputFileOperation.cpp
+ operations/COM_OutputFileOperation.cc
operations/COM_OutputFileOperation.h
- operations/COM_PreviewOperation.cpp
+ operations/COM_PreviewOperation.cc
operations/COM_PreviewOperation.h
- operations/COM_SplitOperation.cpp
+ operations/COM_SplitOperation.cc
operations/COM_SplitOperation.h
- operations/COM_ViewerOperation.cpp
+ operations/COM_ViewerOperation.cc
operations/COM_ViewerOperation.h
- operations/COM_ZCombineOperation.cpp
+ operations/COM_ZCombineOperation.cc
operations/COM_ZCombineOperation.h
- operations/COM_ChangeHSVOperation.cpp
+ operations/COM_ChangeHSVOperation.cc
operations/COM_ChangeHSVOperation.h
- operations/COM_ChannelMatteOperation.cpp
+ operations/COM_ChannelMatteOperation.cc
operations/COM_ChannelMatteOperation.h
- operations/COM_ChromaMatteOperation.cpp
+ operations/COM_ChromaMatteOperation.cc
operations/COM_ChromaMatteOperation.h
- operations/COM_ColorCurveOperation.cpp
+ operations/COM_ColorCurveOperation.cc
operations/COM_ColorCurveOperation.h
- operations/COM_ColorExposureOperation.cpp
+ operations/COM_ColorExposureOperation.cc
operations/COM_ColorExposureOperation.h
- operations/COM_ColorMatteOperation.cpp
+ operations/COM_ColorMatteOperation.cc
operations/COM_ColorMatteOperation.h
- operations/COM_ColorRampOperation.cpp
+ operations/COM_ColorRampOperation.cc
operations/COM_ColorRampOperation.h
- operations/COM_CurveBaseOperation.cpp
+ operations/COM_CurveBaseOperation.cc
operations/COM_CurveBaseOperation.h
- operations/COM_DifferenceMatteOperation.cpp
+ operations/COM_DifferenceMatteOperation.cc
operations/COM_DifferenceMatteOperation.h
- operations/COM_DistanceRGBMatteOperation.cpp
+ operations/COM_DistanceRGBMatteOperation.cc
operations/COM_DistanceRGBMatteOperation.h
- operations/COM_DistanceYCCMatteOperation.cpp
+ operations/COM_DistanceYCCMatteOperation.cc
operations/COM_DistanceYCCMatteOperation.h
- operations/COM_HueSaturationValueCorrectOperation.cpp
+ operations/COM_HueSaturationValueCorrectOperation.cc
operations/COM_HueSaturationValueCorrectOperation.h
- operations/COM_LuminanceMatteOperation.cpp
+ operations/COM_LuminanceMatteOperation.cc
operations/COM_LuminanceMatteOperation.h
- operations/COM_VectorCurveOperation.cpp
+ operations/COM_VectorCurveOperation.cc
operations/COM_VectorCurveOperation.h
- operations/COM_BrightnessOperation.cpp
+ operations/COM_BrightnessOperation.cc
operations/COM_BrightnessOperation.h
- operations/COM_ColorCorrectionOperation.cpp
+ operations/COM_ColorCorrectionOperation.cc
operations/COM_ColorCorrectionOperation.h
- operations/COM_GammaOperation.cpp
+ operations/COM_GammaOperation.cc
operations/COM_GammaOperation.h
- operations/COM_MixOperation.cpp
+ operations/COM_MixOperation.cc
operations/COM_MixOperation.h
- operations/COM_ReadBufferOperation.cpp
+ operations/COM_ReadBufferOperation.cc
operations/COM_ReadBufferOperation.h
- operations/COM_SetColorOperation.cpp
+ operations/COM_SetColorOperation.cc
operations/COM_SetColorOperation.h
- operations/COM_SetValueOperation.cpp
+ operations/COM_SetValueOperation.cc
operations/COM_SetValueOperation.h
- operations/COM_SetVectorOperation.cpp
+ operations/COM_SetVectorOperation.cc
operations/COM_SetVectorOperation.h
- operations/COM_WriteBufferOperation.cpp
+ operations/COM_WriteBufferOperation.cc
operations/COM_WriteBufferOperation.h
- operations/COM_MathBaseOperation.cpp
+ operations/COM_MathBaseOperation.cc
operations/COM_MathBaseOperation.h
- operations/COM_AlphaOverKeyOperation.cpp
+ operations/COM_AlphaOverKeyOperation.cc
operations/COM_AlphaOverKeyOperation.h
- operations/COM_AlphaOverMixedOperation.cpp
+ operations/COM_AlphaOverMixedOperation.cc
operations/COM_AlphaOverMixedOperation.h
- operations/COM_AlphaOverPremultiplyOperation.cpp
+ operations/COM_AlphaOverPremultiplyOperation.cc
operations/COM_AlphaOverPremultiplyOperation.h
- operations/COM_ColorBalanceASCCDLOperation.cpp
+ operations/COM_ColorBalanceASCCDLOperation.cc
operations/COM_ColorBalanceASCCDLOperation.h
- operations/COM_ColorBalanceLGGOperation.cpp
+ operations/COM_ColorBalanceLGGOperation.cc
operations/COM_ColorBalanceLGGOperation.h
- operations/COM_InvertOperation.cpp
+ operations/COM_InvertOperation.cc
operations/COM_InvertOperation.h
- operations/COM_MapRangeOperation.cpp
+ operations/COM_MapRangeOperation.cc
operations/COM_MapRangeOperation.h
- operations/COM_MapValueOperation.cpp
+ operations/COM_MapValueOperation.cc
operations/COM_MapValueOperation.h
- operations/COM_SetAlphaMultiplyOperation.cpp
+ operations/COM_SetAlphaMultiplyOperation.cc
operations/COM_SetAlphaMultiplyOperation.h
- operations/COM_SetAlphaReplaceOperation.cpp
+ operations/COM_SetAlphaReplaceOperation.cc
operations/COM_SetAlphaReplaceOperation.h
# Distort operation
- operations/COM_DisplaceOperation.cpp
+ operations/COM_DisplaceOperation.cc
operations/COM_DisplaceOperation.h
- operations/COM_DisplaceSimpleOperation.cpp
+ operations/COM_DisplaceSimpleOperation.cc
operations/COM_DisplaceSimpleOperation.h
- operations/COM_FlipOperation.cpp
+ operations/COM_FlipOperation.cc
operations/COM_FlipOperation.h
- operations/COM_MapUVOperation.cpp
+ operations/COM_MapUVOperation.cc
operations/COM_MapUVOperation.h
- operations/COM_PlaneCornerPinOperation.cpp
+ operations/COM_PlaneCornerPinOperation.cc
operations/COM_PlaneCornerPinOperation.h
- operations/COM_PlaneDistortCommonOperation.cpp
+ operations/COM_PlaneDistortCommonOperation.cc
operations/COM_PlaneDistortCommonOperation.h
- operations/COM_PlaneTrackOperation.cpp
+ operations/COM_PlaneTrackOperation.cc
operations/COM_PlaneTrackOperation.h
- operations/COM_ProjectorLensDistortionOperation.cpp
+ operations/COM_ProjectorLensDistortionOperation.cc
operations/COM_ProjectorLensDistortionOperation.h
- operations/COM_RotateOperation.cpp
+ operations/COM_RotateOperation.cc
operations/COM_RotateOperation.h
- operations/COM_ScaleOperation.cpp
+ operations/COM_ScaleOperation.cc
operations/COM_ScaleOperation.h
- operations/COM_ScreenLensDistortionOperation.cpp
+ operations/COM_ScreenLensDistortionOperation.cc
operations/COM_ScreenLensDistortionOperation.h
- operations/COM_TranslateOperation.cpp
+ operations/COM_TranslateOperation.cc
operations/COM_TranslateOperation.h
- operations/COM_WrapOperation.cpp
+ operations/COM_WrapOperation.cc
operations/COM_WrapOperation.h
# Filter operations
- operations/COM_ConvolutionEdgeFilterOperation.cpp
+ operations/COM_ConvolutionEdgeFilterOperation.cc
operations/COM_ConvolutionEdgeFilterOperation.h
- operations/COM_ConvolutionFilterOperation.cpp
+ operations/COM_ConvolutionFilterOperation.cc
operations/COM_ConvolutionFilterOperation.h
- operations/COM_DenoiseOperation.cpp
+ operations/COM_DenoiseOperation.cc
operations/COM_DenoiseOperation.h
- operations/COM_DespeckleOperation.cpp
+ operations/COM_DespeckleOperation.cc
operations/COM_DespeckleOperation.h
- operations/COM_DilateErodeOperation.cpp
+ operations/COM_DilateErodeOperation.cc
operations/COM_DilateErodeOperation.h
- operations/COM_GlareBaseOperation.cpp
+ operations/COM_GlareBaseOperation.cc
operations/COM_GlareBaseOperation.h
- operations/COM_GlareFogGlowOperation.cpp
+ operations/COM_GlareFogGlowOperation.cc
operations/COM_GlareFogGlowOperation.h
- operations/COM_GlareGhostOperation.cpp
+ operations/COM_GlareGhostOperation.cc
operations/COM_GlareGhostOperation.h
- operations/COM_GlareSimpleStarOperation.cpp
+ operations/COM_GlareSimpleStarOperation.cc
operations/COM_GlareSimpleStarOperation.h
- operations/COM_GlareStreaksOperation.cpp
+ operations/COM_GlareStreaksOperation.cc
operations/COM_GlareStreaksOperation.h
- operations/COM_GlareThresholdOperation.cpp
+ operations/COM_GlareThresholdOperation.cc
operations/COM_GlareThresholdOperation.h
- operations/COM_InpaintOperation.cpp
+ operations/COM_InpaintOperation.cc
operations/COM_InpaintOperation.h
- operations/COM_SetSamplerOperation.cpp
+ operations/COM_SetSamplerOperation.cc
operations/COM_SetSamplerOperation.h
# Convert operations
- operations/COM_ConvertOperation.cpp
+ operations/COM_ConvertOperation.cc
operations/COM_ConvertOperation.h
- operations/COM_IDMaskOperation.cpp
+ operations/COM_IDMaskOperation.cc
operations/COM_IDMaskOperation.h
- operations/COM_DotproductOperation.cpp
+ operations/COM_DotproductOperation.cc
operations/COM_DotproductOperation.h
# Matte operation
- operations/COM_BoxMaskOperation.cpp
+ operations/COM_BoxMaskOperation.cc
operations/COM_BoxMaskOperation.h
- operations/COM_EllipseMaskOperation.cpp
+ operations/COM_EllipseMaskOperation.cc
operations/COM_EllipseMaskOperation.h
- operations/COM_ConvertColorProfileOperation.cpp
+ operations/COM_ConvertColorProfileOperation.cc
operations/COM_ConvertColorProfileOperation.h
- operations/COM_MovieClipOperation.cpp
+ operations/COM_MovieClipOperation.cc
operations/COM_MovieClipOperation.h
- operations/COM_AntiAliasOperation.cpp
+ operations/COM_AntiAliasOperation.cc
operations/COM_AntiAliasOperation.h
- operations/COM_MaskOperation.cpp
+ operations/COM_MaskOperation.cc
operations/COM_MaskOperation.h
)
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index ba66d7f0dfe..4aae5471858 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -113,11 +113,11 @@ extern "C" {
*
* When the chunk-order is determined, the first few chunks will be checked if they can be scheduled.
* Chunks can have three states:
- * - [@ref ChunkExecutionState.COM_ES_NOT_SCHEDULED]:
+ * - [@ref eChunkExecutionState.NOT_SCHEDULED]:
* Chunk is not yet scheduled, or dependencies are not met.
- * - [@ref ChunkExecutionState.COM_ES_SCHEDULED]:
+ * - [@ref eChunkExecutionState.SCHEDULED]:
* All dependencies are met, chunk is scheduled, but not finished.
- * - [@ref ChunkExecutionState.COM_ES_EXECUTED]:
+ * - [@ref eChunkExecutionState.EXECUTED]:
* Chunk is finished.
*
* \see ExecutionGroup.execute
diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cc
index 7ea12866148..b520a437008 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.cpp
+++ b/source/blender/compositor/intern/COM_CPUDevice.cc
@@ -24,8 +24,8 @@ CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id)
void CPUDevice::execute(WorkPackage *work)
{
- const unsigned int chunkNumber = work->getChunkNumber();
- ExecutionGroup *executionGroup = work->getExecutionGroup();
+ const unsigned int chunkNumber = work->chunk_number;
+ ExecutionGroup *executionGroup = work->execution_group;
rcti rect;
executionGroup->determineChunkRect(&rect, chunkNumber);
diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cpp b/source/blender/compositor/intern/COM_ChunkOrder.cc
index 3baa50da487..3baa50da487 100644
--- a/source/blender/compositor/intern/COM_ChunkOrder.cpp
+++ b/source/blender/compositor/intern/COM_ChunkOrder.cc
diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc
index bbc98d086a6..d31ff518ecd 100644
--- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp
+++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc
@@ -19,18 +19,11 @@
#include "COM_ChunkOrderHotspot.h"
#include <cmath>
-ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition)
-{
- x = x;
- y = y;
- addition = addition;
-}
-
double ChunkOrderHotspot::calc_distance(int x, int y)
{
- int dx = x - x;
- int dy = y - y;
+ int dx = this->x - x;
+ int dy = this->y - y;
double result = sqrt((double)(dx * dx + dy * dy));
- result += (double)addition;
+ result += (double)this->addition;
return result;
}
diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h
index af0cf897673..d7f40921836 100644
--- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h
+++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h
@@ -27,8 +27,9 @@ struct ChunkOrderHotspot {
int y;
float addition;
- public:
- ChunkOrderHotspot(int x, int y, float addition);
+ ChunkOrderHotspot(int x, int y, float addition) : x(x), y(y), addition(addition)
+ {
+ }
double calc_distance(int x, int y);
diff --git a/source/blender/compositor/intern/COM_CompositorContext.cpp b/source/blender/compositor/intern/COM_CompositorContext.cc
index 2e168221b7b..2e168221b7b 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.cpp
+++ b/source/blender/compositor/intern/COM_CompositorContext.cc
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cc
index 08035940667..91439f54710 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -115,9 +115,9 @@
#include "COM_ViewerNode.h"
#include "COM_ZCombineNode.h"
-bool Converter::is_fast_node(bNode *b_node)
+bool COM_bnode_is_fast_node(const bNode &b_node)
{
- return !ELEM(b_node->type,
+ return !ELEM(b_node.type,
CMP_NODE_BLUR,
CMP_NODE_VECBLUR,
CMP_NODE_BILATERALBLUR,
@@ -132,7 +132,7 @@ bool Converter::is_fast_node(bNode *b_node)
CMP_NODE_DENOISE);
}
-Node *Converter::convert(bNode *b_node)
+Node *COM_convert_bnode(bNode *b_node)
{
Node *node = nullptr;
@@ -406,6 +406,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_SUNBEAMS:
node = new SunBeamsNode(b_node);
break;
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
+ node = new CryptomatteLegacyNode(b_node);
+ break;
case CMP_NODE_CRYPTOMATTE:
node = new CryptomatteNode(b_node);
break;
@@ -419,36 +422,37 @@ Node *Converter::convert(bNode *b_node)
return node;
}
-NodeOperation *Converter::convertDataType(NodeOperationOutput *from, NodeOperationInput *to)
+/* TODO(jbakker): make this an std::optional<NodeOperation>. */
+NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to)
{
- DataType fromDatatype = from->getDataType();
- DataType toDatatype = to->getDataType();
+ const DataType src_data_type = from.getDataType();
+ const DataType dst_data_type = to.getDataType();
- if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_COLOR) {
+ if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) {
return new ConvertValueToColorOperation();
}
- if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_VECTOR) {
+ if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) {
return new ConvertValueToVectorOperation();
}
- if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VALUE) {
+ if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) {
return new ConvertColorToValueOperation();
}
- if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VECTOR) {
+ if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) {
return new ConvertColorToVectorOperation();
}
- if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_VALUE) {
+ if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) {
return new ConvertVectorToValueOperation();
}
- if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_COLOR) {
+ if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) {
return new ConvertVectorToColorOperation();
}
return nullptr;
}
-void Converter::convertResolution(NodeOperationBuilder &builder,
- NodeOperationOutput *fromSocket,
- NodeOperationInput *toSocket)
+void COM_convert_resolution(NodeOperationBuilder &builder,
+ NodeOperationOutput *fromSocket,
+ NodeOperationInput *toSocket)
{
InputResizeMode mode = toSocket->getResizeMode();
diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h
index fe3b8b75ccc..59be34bf0e3 100644
--- a/source/blender/compositor/intern/COM_Converter.h
+++ b/source/blender/compositor/intern/COM_Converter.h
@@ -31,56 +31,37 @@ class NodeOperationOutput;
class NodeOperationBuilder;
/**
- * \brief Conversion methods for the compositor
+ * \brief Wraps a bNode in its Node instance.
+ *
+ * For all nodetypes a wrapper class is created.
+ *
+ * \note When adding a new node to blender, this method needs to be changed to return the correct
+ * Node instance.
+ *
+ * \see Node
*/
-class Converter {
- public:
- /**
- * \brief Convert/wraps a bNode in its Node instance.
- *
- * For all nodetypes a wrapper class is created.
- *
- * \note When adding a new node to blender, this method needs to be changed to return the correct
- * Node instance.
- *
- * \see Node
- */
- static Node *convert(bNode *b_node);
-
- /**
- * \brief True if the node is considered 'fast'.
- *
- * Slow nodes will be skipped if fast execution is required.
- */
- static bool is_fast_node(bNode *b_node);
+Node *COM_convert_bnode(bNode *b_node);
- /**
- * \brief This method will add a datetype conversion rule when the to-socket does not support the
- * from-socket actual data type.
- *
- * \note this method is called when conversion is needed.
- *
- * \param link: the NodeLink what needs conversion
- * \param system: the ExecutionSystem to add the conversion to.
- * \see NodeLink - a link between two sockets
- */
- static NodeOperation *convertDataType(NodeOperationOutput *from, NodeOperationInput *to);
+/**
+ * \brief True if the node is considered 'fast'.
+ *
+ * Slow nodes will be skipped if fast execution is required.
+ */
+bool COM_bnode_is_fast_node(const bNode &b_node);
- /**
- * \brief This method will add a resolution rule based on the settings of the NodeInput.
- *
- * \note Conversion logic is implemented in this method
- * \see InputSocketResizeMode for the possible conversions.
- *
- * \param link: the NodeLink what needs conversion
- * \param system: the ExecutionSystem to add the conversion to.
- * \see NodeLink - a link between two sockets
- */
- static void convertResolution(NodeOperationBuilder &builder,
- NodeOperationOutput *fromSocket,
- NodeOperationInput *toSocket);
+/**
+ * \brief This function will add a datetype conversion rule when the to-socket does not support the
+ * from-socket actual data type.
+ */
+NodeOperation *COM_convert_data_type(const NodeOperationOutput &from,
+ const NodeOperationInput &to);
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("COM:Converter")
-#endif
-};
+/**
+ * \brief This function will add a resolution rule based on the settings of the NodeInput.
+ *
+ * \note Conversion logic is implemented in this function.
+ * \see InputSocketResizeMode for the possible conversions.
+ */
+void COM_convert_resolution(NodeOperationBuilder &builder,
+ NodeOperationOutput *fromSocket,
+ NodeOperationInput *toSocket);
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cc
index b49d575cade..c97d3a4a00a 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -56,9 +56,7 @@ std::string DebugInfo::node_name(const Node *node)
if (it != m_node_names.end()) {
return it->second;
}
- else {
- return "";
- }
+ return "";
}
std::string DebugInfo::operation_name(const NodeOperation *op)
@@ -67,9 +65,7 @@ std::string DebugInfo::operation_name(const NodeOperation *op)
if (it != m_op_names.end()) {
return it->second;
}
- else {
- return "";
- }
+ return "";
}
void DebugInfo::convert_started()
@@ -81,10 +77,8 @@ void DebugInfo::execute_started(const ExecutionSystem *system)
{
m_file_index = 1;
m_group_states.clear();
- for (ExecutionSystem::Groups::const_iterator it = system->m_groups.begin();
- it != system->m_groups.end();
- ++it) {
- m_group_states[*it] = EG_WAIT;
+ for (ExecutionGroup *execution_group : system->m_groups) {
+ m_group_states[execution_group] = EG_WAIT;
}
}
@@ -320,26 +314,11 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rankdir=LR\r\n");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "splines=false\r\n");
-# if 0
- for (ExecutionSystem::Operations::const_iterator it = system->m_operations.begin();
- it != system->m_operations.end();
- ++it) {
- NodeOperation *op = *it;
- len += snprintf(str + len,
- maxlen > len ? maxlen - len : 0,
- "// OPERATION: %s\r\n",
- node->getbNode()->typeinfo->ui_name);
- }
-# endif
-
- int totops = system->m_operations.size();
- int totgroups = system->m_groups.size();
std::map<NodeOperation *, std::vector<std::string>> op_groups;
- for (int i = 0; i < totgroups; i++) {
- const ExecutionGroup *group = system->m_groups[i];
-
- len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", i);
- len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "subgraph cluster_%d{\r\n", i);
+ int index = 0;
+ for (const ExecutionGroup *group : system->m_groups) {
+ len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", index);
+ len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "subgraph cluster_%d{\r\n", index);
/* used as a check for executing group */
if (m_group_states[group] == EG_WAIT) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=dashed\r\n");
@@ -355,10 +334,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=chartreuse4\r\n");
}
- for (ExecutionGroup::Operations::const_iterator it = group->m_operations.begin();
- it != group->m_operations.end();
- ++it) {
- NodeOperation *operation = *it;
+ for (NodeOperation *operation : group->m_operations) {
sprintf(strbuf, "_%p", group);
op_groups[operation].push_back(std::string(strbuf));
@@ -367,30 +343,23 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
system, operation, group, str + len, maxlen > len ? maxlen - len : 0);
}
- // len += snprintf(str+len,
- // maxlen>len ? maxlen-len : 0,
- // "// OUTPUTOPERATION: %p\r\n", group->getOutputOperation());
- // len += snprintf(
- // str+len, maxlen>len ? maxlen-len : 0,
- // " O_%p\r\n", group->getOutputOperation());
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n");
+ index++;
}
/* operations not included in any group */
- for (int j = 0; j < totops; j++) {
- NodeOperation *operation = system->m_operations[j];
+ for (NodeOperation *operation : system->m_operations) {
if (op_groups.find(operation) != op_groups.end()) {
continue;
}
op_groups[operation].push_back(std::string(""));
- len += graphviz_operation(system, operation, 0, str + len, maxlen > len ? maxlen - len : 0);
+ len += graphviz_operation(
+ system, operation, nullptr, str + len, maxlen > len ? maxlen - len : 0);
}
- for (int i = 0; i < totops; i++) {
- NodeOperation *operation = system->m_operations[i];
-
+ for (NodeOperation *operation : system->m_operations) {
if (operation->isReadBufferOperation()) {
ReadBufferOperation *read = (ReadBufferOperation *)operation;
WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation();
@@ -411,12 +380,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
}
- for (int i = 0; i < totops; i++) {
- NodeOperation *op = system->m_operations[i];
-
- for (NodeOperation::Inputs::const_iterator it = op->m_inputs.begin(); it != op->m_inputs.end();
- ++it) {
- NodeOperationInput *to = *it;
+ for (NodeOperation *op : system->m_operations) {
+ for (NodeOperationInput *to : op->m_inputs) {
NodeOperationOutput *from = to->getLink();
if (!from) {
@@ -452,7 +417,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
for (int l = 0; l < to_groups.size(); l++) {
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
- "\"O_%p%s\":\"OUT_%p\":e -> \"O_%p%s\":\"IN_%p\":w",
+ R"("O_%p%s":"OUT_%p":e -> "O_%p%s":"IN_%p":w)",
from_op,
from_groups[k].c_str(),
from,
diff --git a/source/blender/compositor/intern/COM_Device.cpp b/source/blender/compositor/intern/COM_Device.cc
index 38a22369005..38a22369005 100644
--- a/source/blender/compositor/intern/COM_Device.cpp
+++ b/source/blender/compositor/intern/COM_Device.cc
diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h
index bb95f1e953c..0b0f0f5c1c6 100644
--- a/source/blender/compositor/intern/COM_Device.h
+++ b/source/blender/compositor/intern/COM_Device.h
@@ -55,7 +55,7 @@ class Device {
* \brief execute a WorkPackage
* \param work: the WorkPackage to execute
*/
- virtual void execute(WorkPackage *work) = 0;
+ virtual void execute(struct WorkPackage *work) = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:Device")
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cc
index 9c21c91c370..37623228183 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc
@@ -43,20 +43,19 @@
ExecutionGroup::ExecutionGroup()
{
- this->m_isOutput = false;
+ this->m_is_output = false;
this->m_complex = false;
- this->m_chunkExecutionStates = nullptr;
this->m_bTree = nullptr;
this->m_height = 0;
this->m_width = 0;
- this->m_cachedMaxReadBufferOffset = 0;
- this->m_numberOfXChunks = 0;
- this->m_numberOfYChunks = 0;
- this->m_numberOfChunks = 0;
+ this->m_max_read_buffer_offset = 0;
+ this->m_x_chunks_len = 0;
+ this->m_y_chunks_len = 0;
+ this->m_chunks_len = 0;
this->m_initialized = false;
this->m_openCL = false;
this->m_singleThreaded = false;
- this->m_chunksFinished = 0;
+ this->m_chunks_finished = 0;
BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0);
this->m_executionStartTime = 0;
}
@@ -108,7 +107,7 @@ bool ExecutionGroup::addOperation(NodeOperation *operation)
m_initialized = true;
}
- m_operations.push_back(operation);
+ m_operations.append(operation);
return true;
}
@@ -121,45 +120,36 @@ NodeOperation *ExecutionGroup::getOutputOperation() const
void ExecutionGroup::initExecution()
{
- if (this->m_chunkExecutionStates != nullptr) {
- MEM_freeN(this->m_chunkExecutionStates);
- }
- unsigned int index;
+ m_chunk_execution_states.clear();
determineNumberOfChunks();
- this->m_chunkExecutionStates = nullptr;
- if (this->m_numberOfChunks != 0) {
- this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN(
- sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__);
- for (index = 0; index < this->m_numberOfChunks; index++) {
- this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED;
+ if (this->m_chunks_len != 0) {
+ m_chunk_execution_states.resize(this->m_chunks_len);
+ for (int index = 0; index < this->m_chunks_len; index++) {
+ m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED;
}
}
- unsigned int maxNumber = 0;
+ unsigned int max_offset = 0;
- for (index = 0; index < this->m_operations.size(); index++) {
- NodeOperation *operation = this->m_operations[index];
+ for (NodeOperation *operation : m_operations) {
if (operation->isReadBufferOperation()) {
- ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
- this->m_cachedReadOperations.push_back(readOperation);
- maxNumber = max(maxNumber, readOperation->getOffset());
+ ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
+ this->m_read_operations.append(readOperation);
+ max_offset = MAX2(max_offset, readOperation->getOffset());
}
}
- maxNumber++;
- this->m_cachedMaxReadBufferOffset = maxNumber;
+ max_offset++;
+ this->m_max_read_buffer_offset = max_offset;
}
void ExecutionGroup::deinitExecution()
{
- if (this->m_chunkExecutionStates != nullptr) {
- MEM_freeN(this->m_chunkExecutionStates);
- this->m_chunkExecutionStates = nullptr;
- }
- this->m_numberOfChunks = 0;
- this->m_numberOfXChunks = 0;
- this->m_numberOfYChunks = 0;
- this->m_cachedReadOperations.clear();
+ m_chunk_execution_states.clear();
+ this->m_chunks_len = 0;
+ this->m_x_chunks_len = 0;
+ this->m_y_chunks_len = 0;
+ this->m_read_operations.clear();
this->m_bTree = nullptr;
}
void ExecutionGroup::determineResolution(unsigned int resolution[2])
@@ -174,17 +164,17 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2])
void ExecutionGroup::determineNumberOfChunks()
{
if (this->m_singleThreaded) {
- this->m_numberOfXChunks = 1;
- this->m_numberOfYChunks = 1;
- this->m_numberOfChunks = 1;
+ this->m_x_chunks_len = 1;
+ this->m_y_chunks_len = 1;
+ this->m_chunks_len = 1;
}
else {
const float chunkSizef = this->m_chunkSize;
const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
- this->m_numberOfXChunks = ceil(border_width / chunkSizef);
- this->m_numberOfYChunks = ceil(border_height / chunkSizef);
- this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks;
+ this->m_x_chunks_len = ceil(border_width / chunkSizef);
+ this->m_y_chunks_len = ceil(border_height / chunkSizef);
+ this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len;
}
}
@@ -202,20 +192,20 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
if (bTree->test_break && bTree->test_break(bTree->tbh)) {
return;
} /** \note Early break out for blur and preview nodes. */
- if (this->m_numberOfChunks == 0) {
+ if (this->m_chunks_len == 0) {
return;
} /** \note Early break out. */
unsigned int chunkNumber;
this->m_executionStartTime = PIL_check_seconds_timer();
- this->m_chunksFinished = 0;
+ this->m_chunks_finished = 0;
this->m_bTree = bTree;
unsigned int index;
- unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(
- sizeof(unsigned int) * this->m_numberOfChunks, __func__);
+ unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len,
+ __func__);
- for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) {
+ for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) {
chunkOrder[chunkNumber] = chunkNumber;
}
NodeOperation *operation = this->getOutputOperation();
@@ -235,9 +225,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
switch (chunkorder) {
case COM_TO_RANDOM:
- for (index = 0; index < 2 * this->m_numberOfChunks; index++) {
- int index1 = rand() % this->m_numberOfChunks;
- int index2 = rand() % this->m_numberOfChunks;
+ for (index = 0; index < 2 * this->m_chunks_len; index++) {
+ int index1 = rand() % this->m_chunks_len;
+ int index2 = rand() % this->m_chunks_len;
int s = chunkOrder[index1];
chunkOrder[index1] = chunkOrder[index2];
chunkOrder[index2] = s;
@@ -247,9 +237,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
ChunkOrderHotspot *hotspots[1];
hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f);
rcti rect;
- ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(
- sizeof(ChunkOrder) * this->m_numberOfChunks, __func__);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len,
+ __func__);
+ for (index = 0; index < this->m_chunks_len; index++) {
determineChunkRect(&rect, index);
chunkOrders[index].number = index;
chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin;
@@ -257,8 +247,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].update_distance(hotspots, 1);
}
- std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]);
+ for (index = 0; index < this->m_chunks_len; index++) {
chunkOrder[index] = chunkOrders[index].number;
}
@@ -275,7 +265,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
unsigned int bx = mx + 2 * tx;
unsigned int by = my + 2 * ty;
- float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER;
+ float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER;
hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0);
hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1);
hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2);
@@ -286,9 +276,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7);
hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8);
rcti rect;
- ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(
- sizeof(ChunkOrder) * this->m_numberOfChunks, __func__);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len,
+ __func__);
+ for (index = 0; index < this->m_chunks_len; index++) {
determineChunkRect(&rect, index);
chunkOrders[index].number = index;
chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin;
@@ -296,9 +286,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].update_distance(hotspots, 9);
}
- std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ for (index = 0; index < this->m_chunks_len; index++) {
chunkOrder[index] = chunkOrders[index].number;
}
@@ -332,31 +322,35 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
finished = true;
int numberEvaluated = 0;
- for (index = startIndex;
- index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated;
+ for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated;
index++) {
chunkNumber = chunkOrder[index];
- int yChunk = chunkNumber / this->m_numberOfXChunks;
- int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
- const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber];
- if (state == COM_ES_NOT_SCHEDULED) {
- scheduleChunkWhenPossible(graph, xChunk, yChunk);
- finished = false;
- startEvaluated = true;
- numberEvaluated++;
-
- if (bTree->update_draw) {
- bTree->update_draw(bTree->udh);
+ int yChunk = chunkNumber / this->m_x_chunks_len;
+ int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len);
+ switch (m_chunk_execution_states[chunkNumber]) {
+ case eChunkExecutionState::NOT_SCHEDULED: {
+ scheduleChunkWhenPossible(graph, xChunk, yChunk);
+ finished = false;
+ startEvaluated = true;
+ numberEvaluated++;
+
+ if (bTree->update_draw) {
+ bTree->update_draw(bTree->udh);
+ }
+ break;
}
- }
- else if (state == COM_ES_SCHEDULED) {
- finished = false;
- startEvaluated = true;
- numberEvaluated++;
- }
- else if (state == COM_ES_EXECUTED && !startEvaluated) {
- startIndex = index + 1;
- }
+ case eChunkExecutionState::SCHEDULED: {
+ finished = false;
+ startEvaluated = true;
+ numberEvaluated++;
+ break;
+ }
+ case eChunkExecutionState::EXECUTED: {
+ if (!startEvaluated) {
+ startIndex = index + 1;
+ }
+ }
+ };
}
WorkScheduler::finish();
@@ -374,17 +368,14 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
{
rcti rect;
- vector<MemoryProxy *> memoryproxies;
- unsigned int index;
+ std::vector<MemoryProxy *> memoryproxies;
determineChunkRect(&rect, chunkNumber);
this->determineDependingMemoryProxies(&memoryproxies);
MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN(
- sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__);
+ sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__);
rcti output;
- for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
- ReadBufferOperation *readOperation =
- (ReadBufferOperation *)this->m_cachedReadOperations[index];
+ for (ReadBufferOperation *readOperation : m_read_operations) {
MemoryProxy *memoryProxy = readOperation->getMemoryProxy();
this->determineDependingAreaOfInterest(&rect, readOperation, &output);
MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(
@@ -405,13 +396,13 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem
void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
{
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
- this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) {
+ this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED;
}
- atomic_add_and_fetch_u(&this->m_chunksFinished, 1);
+ atomic_add_and_fetch_u(&this->m_chunks_finished, 1);
if (memoryBuffers) {
- for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
+ for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) {
MemoryBuffer *buffer = memoryBuffers[index];
if (buffer) {
if (buffer->isTemporarily()) {
@@ -424,16 +415,16 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
}
if (this->m_bTree) {
// status report is only performed for top level Execution Groups.
- float progress = this->m_chunksFinished;
- progress /= this->m_numberOfChunks;
+ float progress = this->m_chunks_finished;
+ progress /= this->m_chunks_len;
this->m_bTree->progress(this->m_bTree->prh, progress);
char buf[128];
BLI_snprintf(buf,
sizeof(buf),
TIP_("Compositing | Tile %u-%u"),
- this->m_chunksFinished,
- this->m_numberOfChunks);
+ this->m_chunks_finished,
+ this->m_chunks_len);
this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
}
}
@@ -452,20 +443,20 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect,
else {
const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin;
const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin;
- const unsigned int width = min((unsigned int)this->m_viewerBorder.xmax, this->m_width);
- const unsigned int height = min((unsigned int)this->m_viewerBorder.ymax, this->m_height);
+ const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width);
+ const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height);
BLI_rcti_init(rect,
- min(minx, this->m_width),
- min(minx + this->m_chunkSize, width),
- min(miny, this->m_height),
- min(miny + this->m_chunkSize, height));
+ MIN2(minx, this->m_width),
+ MIN2(minx + this->m_chunkSize, width),
+ MIN2(miny, this->m_height),
+ MIN2(miny + this->m_chunkSize, height));
}
}
void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const
{
- const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks;
- const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
+ const unsigned int yChunk = chunkNumber / this->m_x_chunks_len;
+ const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len);
determineChunkRect(rect, xChunk, yChunk);
}
@@ -500,8 +491,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area
int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize;
minxchunk = max_ii(minxchunk, 0);
minychunk = max_ii(minychunk, 0);
- maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks);
- maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks);
+ maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len);
+ maxychunk = min_ii(maxychunk, (int)m_y_chunks_len);
bool result = true;
for (indexx = minxchunk; indexx < maxxchunk; indexx++) {
@@ -517,8 +508,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area
bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
{
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) {
- this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED;
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) {
+ this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED;
WorkScheduler::schedule(this, chunkNumber);
return true;
}
@@ -527,25 +518,25 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk)
{
- if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) {
+ if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) {
return true;
}
- if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) {
+ if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) {
return true;
}
- int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk;
+ int chunkNumber = yChunk * this->m_x_chunks_len + xChunk;
// chunk is already executed
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) {
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) {
return true;
}
// chunk is scheduled, but not executed
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) {
return false;
}
// chunk is nor executed nor scheduled.
- vector<MemoryProxy *> memoryProxies;
+ std::vector<MemoryProxy *> memoryProxies;
this->determineDependingMemoryProxies(&memoryProxies);
rcti rect;
@@ -554,9 +545,8 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun
bool canBeExecuted = true;
rcti area;
- for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
- ReadBufferOperation *readOperation =
- (ReadBufferOperation *)this->m_cachedReadOperations[index];
+ for (index = 0; index < m_read_operations.size(); index++) {
+ ReadBufferOperation *readOperation = m_read_operations[index];
BLI_rcti_init(&area, 0, 0, 0, 0);
MemoryProxy *memoryProxy = memoryProxies[index];
determineDependingAreaOfInterest(&rect, readOperation, &area);
@@ -586,12 +576,9 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input,
this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output);
}
-void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies)
+void ExecutionGroup::determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies)
{
- unsigned int index;
- for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
- ReadBufferOperation *readOperation =
- (ReadBufferOperation *)this->m_cachedReadOperations[index];
+ for (ReadBufferOperation *readOperation : m_read_operations) {
memoryProxies->push_back(readOperation->getMemoryProxy());
}
}
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index dd079415d09..f73f4473b5d 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -23,6 +23,8 @@
#endif
#include "BLI_rect.h"
+#include "BLI_vector.hh"
+
#include "COM_CompositorContext.h"
#include "COM_Device.h"
#include "COM_MemoryProxy.h"
@@ -30,8 +32,6 @@
#include "COM_NodeOperation.h"
#include <vector>
-using std::vector;
-
class ExecutionSystem;
class MemoryProxy;
class ReadBufferOperation;
@@ -41,20 +41,20 @@ class Device;
* \brief the execution state of a chunk in an ExecutionGroup
* \ingroup Execution
*/
-typedef enum ChunkExecutionState {
+enum class eChunkExecutionState {
/**
* \brief chunk is not yet scheduled
*/
- COM_ES_NOT_SCHEDULED = 0,
+ NOT_SCHEDULED = 0,
/**
* \brief chunk is scheduled, but not yet executed
*/
- COM_ES_SCHEDULED = 1,
+ SCHEDULED = 1,
/**
* \brief chunk is executed.
*/
- COM_ES_EXECUTED = 2,
-} ChunkExecutionState;
+ EXECUTED = 2,
+};
/**
* \brief Class ExecutionGroup is a group of Operations that are executed as one.
@@ -63,23 +63,20 @@ typedef enum ChunkExecutionState {
* \ingroup Execution
*/
class ExecutionGroup {
- public:
- typedef std::vector<NodeOperation *> Operations;
-
private:
// fields
/**
* \brief list of operations in this ExecutionGroup
*/
- Operations m_operations;
+ blender::Vector<NodeOperation *> m_operations;
/**
* \brief is this ExecutionGroup an input ExecutionGroup
* an input execution group is a group that is at the end of the calculation
* (the output is important for the user).
*/
- int m_isOutput;
+ bool m_is_output;
/**
* \brief Width of the output
@@ -100,17 +97,17 @@ class ExecutionGroup {
/**
* \brief number of chunks in the x-axis
*/
- unsigned int m_numberOfXChunks;
+ unsigned int m_x_chunks_len;
/**
* \brief number of chunks in the y-axis
*/
- unsigned int m_numberOfYChunks;
+ unsigned int m_y_chunks_len;
/**
* \brief total number of chunks
*/
- unsigned int m_numberOfChunks;
+ unsigned int m_chunks_len;
/**
* \brief contains this ExecutionGroup a complex NodeOperation.
@@ -131,12 +128,12 @@ class ExecutionGroup {
* \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup.
* \note this is used to construct the MemoryBuffers that will be passed during execution.
*/
- unsigned int m_cachedMaxReadBufferOffset;
+ unsigned int m_max_read_buffer_offset;
/**
- * \brief a cached vector of all read operations in the execution group.
+ * \brief All read operations of this execution group.
*/
- Operations m_cachedReadOperations;
+ blender::Vector<ReadBufferOperation *> m_read_operations;
/**
* \brief reference to the original bNodeTree,
@@ -148,15 +145,15 @@ class ExecutionGroup {
/**
* \brief total number of chunks that have been calculated for this ExecutionGroup
*/
- unsigned int m_chunksFinished;
+ unsigned int m_chunks_finished;
/**
- * \brief the chunkExecutionStates holds per chunk the execution state. this state can be
- * - COM_ES_NOT_SCHEDULED: not scheduled
- * - COM_ES_SCHEDULED: scheduled
- * - COM_ES_EXECUTED: executed
+ * \brief m_chunk_execution_states holds per chunk the execution state. this state can be
+ * - eChunkExecutionState::NOT_SCHEDULED: not scheduled
+ * - eChunkExecutionState::SCHEDULED: scheduled
+ * - eChunkExecutionState::EXECUTED: executed
*/
- ChunkExecutionState *m_chunkExecutionStates;
+ blender::Vector<eChunkExecutionState> m_chunk_execution_states;
/**
* \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution
@@ -272,18 +269,18 @@ class ExecutionGroup {
* \note ViewerOperation, CompositeOperation, PreviewOperation.
* \see NodeOperation.isOutputOperation
*/
- int isOutputExecutionGroup() const
+ bool isOutputExecutionGroup() const
{
- return this->m_isOutput;
+ return this->m_is_output;
}
/**
* \brief set whether this ExecutionGroup is an output
* \param isOutput:
*/
- void setOutputExecutionGroup(int isOutput)
+ void setOutputExecutionGroup(bool is_output)
{
- this->m_isOutput = isOutput;
+ this->m_is_output = is_output;
}
/**
@@ -405,7 +402,7 @@ class ExecutionGroup {
* \note the area of the MemoryProxy.creator that has to be executed.
* \param memoryProxies: result
*/
- void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies);
+ void determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies);
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index 4c0c7d2103e..6691e5feb5f 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -121,7 +121,8 @@ ExecutionSystem::~ExecutionSystem()
this->m_groups.clear();
}
-void ExecutionSystem::set_operations(const Operations &operations, const Groups &groups)
+void ExecutionSystem::set_operations(const blender::Vector<NodeOperation *> &operations,
+ const blender::Vector<ExecutionGroup *> &groups)
{
m_operations = operations;
m_groups = groups;
@@ -135,10 +136,7 @@ void ExecutionSystem::execute()
DebugInfo::execute_started(this);
unsigned int order = 0;
- for (vector<NodeOperation *>::iterator iter = this->m_operations.begin();
- iter != this->m_operations.end();
- ++iter) {
- NodeOperation *operation = *iter;
+ for (NodeOperation *operation : m_operations) {
if (operation->isReadBufferOperation()) {
ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
readOperation->setOffset(order);
@@ -179,10 +177,10 @@ void ExecutionSystem::execute()
WorkScheduler::start(this->m_context);
- executeGroups(COM_PRIORITY_HIGH);
+ execute_groups(COM_PRIORITY_HIGH);
if (!this->getContext().isFastCalculation()) {
- executeGroups(COM_PRIORITY_MEDIUM);
- executeGroups(COM_PRIORITY_LOW);
+ execute_groups(COM_PRIORITY_MEDIUM);
+ execute_groups(COM_PRIORITY_LOW);
}
WorkScheduler::finish();
@@ -199,37 +197,23 @@ void ExecutionSystem::execute()
}
}
-void ExecutionSystem::executeGroups(CompositorPriority priority)
+void ExecutionSystem::execute_groups(CompositorPriority priority)
{
- unsigned int index;
- vector<ExecutionGroup *> executionGroups;
- this->findOutputExecutionGroup(&executionGroups, priority);
-
- for (index = 0; index < executionGroups.size(); index++) {
- ExecutionGroup *group = executionGroups[index];
+ blender::Vector<ExecutionGroup *> execution_groups = find_output_execution_groups(priority);
+ for (ExecutionGroup *group : execution_groups) {
group->execute(this);
}
}
-void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result,
- CompositorPriority priority) const
+blender::Vector<ExecutionGroup *> ExecutionSystem::find_output_execution_groups(
+ CompositorPriority priority) const
{
- unsigned int index;
- for (index = 0; index < this->m_groups.size(); index++) {
- ExecutionGroup *group = this->m_groups[index];
- if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
- result->push_back(group);
- }
- }
-}
+ blender::Vector<ExecutionGroup *> result;
-void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const
-{
- unsigned int index;
- for (index = 0; index < this->m_groups.size(); index++) {
- ExecutionGroup *group = this->m_groups[index];
- if (group->isOutputExecutionGroup()) {
- result->push_back(group);
+ for (ExecutionGroup *group : m_groups) {
+ if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
+ result.append(group);
}
}
+ return result;
}
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index 44b47787b06..9a51baf55d7 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -21,12 +21,16 @@ class ExecutionGroup;
#pragma once
#include "BKE_text.h"
+
#include "COM_ExecutionGroup.h"
#include "COM_Node.h"
#include "COM_NodeOperation.h"
+
#include "DNA_color_types.h"
#include "DNA_node_types.h"
+#include "BLI_vector.hh"
+
/**
* \page execution Execution model
* In order to get to an efficient model for execution, several steps are being done. these steps
@@ -79,7 +83,7 @@ class ExecutionGroup;
* - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]:
* Bottom left of the images are aligned.
*
- * \see Converter.convertDataType Datatype conversions
+ * \see COM_convert_data_type Datatype conversions
* \see Converter.convertResolution Image size conversions
*
* \section EM_Step4 Step4: group operations in executions groups
@@ -113,9 +117,6 @@ class ExecutionGroup;
* \brief the ExecutionSystem contains the whole compositor tree.
*/
class ExecutionSystem {
- public:
- typedef std::vector<NodeOperation *> Operations;
- typedef std::vector<ExecutionGroup *> Groups;
private:
/**
@@ -126,24 +127,19 @@ class ExecutionSystem {
/**
* \brief vector of operations
*/
- Operations m_operations;
+ blender::Vector<NodeOperation *> m_operations;
/**
* \brief vector of groups
*/
- Groups m_groups;
+ blender::Vector<ExecutionGroup *> m_groups;
private: // methods
/**
* find all execution group with output nodes
*/
- void findOutputExecutionGroup(vector<ExecutionGroup *> *result,
- CompositorPriority priority) const;
-
- /**
- * find all execution group with output nodes
- */
- void findOutputExecutionGroup(vector<ExecutionGroup *> *result) const;
+ blender::Vector<ExecutionGroup *> find_output_execution_groups(
+ CompositorPriority priority) const;
public:
/**
@@ -167,7 +163,8 @@ class ExecutionSystem {
*/
~ExecutionSystem();
- void set_operations(const Operations &operations, const Groups &groups);
+ void set_operations(const blender::Vector<NodeOperation *> &operations,
+ const blender::Vector<ExecutionGroup *> &groups);
/**
* \brief execute this system
@@ -186,7 +183,7 @@ class ExecutionSystem {
}
private:
- void executeGroups(CompositorPriority priority);
+ void execute_groups(CompositorPriority priority);
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index a13db6bb09e..17a73efeab2 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -20,9 +20,6 @@
#include "MEM_guardedalloc.h"
-using std::max;
-using std::min;
-
static unsigned int determine_num_channels(DataType datatype)
{
switch (datatype) {
@@ -156,10 +153,10 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer)
return;
}
unsigned int otherY;
- unsigned int minX = max(this->m_rect.xmin, otherBuffer->m_rect.xmin);
- unsigned int maxX = min(this->m_rect.xmax, otherBuffer->m_rect.xmax);
- unsigned int minY = max(this->m_rect.ymin, otherBuffer->m_rect.ymin);
- unsigned int maxY = min(this->m_rect.ymax, otherBuffer->m_rect.ymax);
+ unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin);
+ unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax);
+ unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin);
+ unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax);
int offset;
int otherOffset;
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index fce1310f6ef..41e4b86bdd2 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -266,11 +266,6 @@ class MemoryBuffer {
BLI_assert(offset < this->determineBufferSize() * this->m_num_channels);
BLI_assert(!(extend_x == COM_MB_CLIP && (u < m_rect.xmin || u >= m_rect.xmax)) &&
!(extend_y == COM_MB_CLIP && (v < m_rect.ymin || v >= m_rect.ymax)));
-#if 0
- /* always true */
- BLI_assert((int)(MEM_allocN_len(this->m_buffer) / sizeof(*this->m_buffer)) ==
- (int)(this->determineBufferSize() * COM_NUMBER_OF_CHANNELS));
-#endif
float *buffer = &this->m_buffer[offset];
memcpy(result, buffer, sizeof(float) * this->m_num_channels);
}
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cpp b/source/blender/compositor/intern/COM_MemoryProxy.cc
index 7d590cd0ef6..7d590cd0ef6 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.cpp
+++ b/source/blender/compositor/intern/COM_MemoryProxy.cc
diff --git a/source/blender/compositor/intern/COM_MetaData.cpp b/source/blender/compositor/intern/COM_MetaData.cc
index a6306f6c657..a6306f6c657 100644
--- a/source/blender/compositor/intern/COM_MetaData.cpp
+++ b/source/blender/compositor/intern/COM_MetaData.cc
diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h
index 6fdd8d3945e..fa3de895b4e 100644
--- a/source/blender/compositor/intern/COM_MetaData.h
+++ b/source/blender/compositor/intern/COM_MetaData.h
@@ -27,7 +27,6 @@
/* Forward declarations. */
struct RenderResult;
-struct StampData;
/* Cryptomatte includes hash in its meta data keys. The hash is generated from the render
* layer/pass name. Compositing happens without the knowledge of the original layer and pass. The
diff --git a/source/blender/compositor/intern/COM_Node.cpp b/source/blender/compositor/intern/COM_Node.cc
index 897d4e1df02..897d4e1df02 100644
--- a/source/blender/compositor/intern/COM_Node.cpp
+++ b/source/blender/compositor/intern/COM_Node.cc
diff --git a/source/blender/compositor/intern/COM_Node.h b/source/blender/compositor/intern/COM_Node.h
index 15b6fcee3dc..fcbf0aab7e0 100644
--- a/source/blender/compositor/intern/COM_Node.h
+++ b/source/blender/compositor/intern/COM_Node.h
@@ -208,17 +208,6 @@ class Node {
virtual void convertToOperations(NodeConverter &converter,
const CompositorContext &context) const = 0;
- /**
- * Create dummy warning operation, use when we can't get the source data.
- */
- NodeOperation *convertToOperations_invalid_index(NodeConverter *compiler, int index) const;
- /**
- * when a node has no valid data (missing image or a group nodes ID pointer is NULL)
- * call this function from #convertToOperations, this way the node sockets are converted
- * into valid outputs, without this the compositor system gets confused and crashes, see T32490.
- */
- void convertToOperations_invalid(NodeConverter *compiler) const;
-
void setInstanceKey(bNodeInstanceKey instance_key)
{
m_instanceKey = instance_key;
diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cc
index 2db31bd4133..2db31bd4133 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.cpp
+++ b/source/blender/compositor/intern/COM_NodeConverter.cc
diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cc
index b604b8ced88..d8220099f1f 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.cpp
+++ b/source/blender/compositor/intern/COM_NodeGraph.cc
@@ -90,7 +90,7 @@ void NodeGraph::add_node(Node *node,
void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket)
{
- m_links.push_back(Link(fromSocket, toSocket));
+ m_links.append(Link(fromSocket, toSocket));
/* register with the input */
toSocket->setLink(fromSocket);
@@ -103,7 +103,7 @@ void NodeGraph::add_bNodeTree(const CompositorContext &context,
{
const bNodeTree *basetree = context.getbNodeTree();
- /* update viewers in the active edittree as well the base tree (for backdrop) */
+ /* Update viewers in the active edit-tree as well the base tree (for backdrop). */
bool is_active_group = (parent_key.value == basetree->active_viewer_key.value);
/* add all nodes of the tree to the node list */
@@ -113,7 +113,7 @@ void NodeGraph::add_bNodeTree(const CompositorContext &context,
}
NodeRange node_range(m_nodes.begin() + nodes_start, m_nodes.end());
- /* add all nodelinks of the tree to the link list */
+ /* Add all node-links of the tree to the link list. */
for (bNodeLink *nodelink = (bNodeLink *)tree->links.first; nodelink; nodelink = nodelink->next) {
add_bNodeLink(node_range, nodelink);
}
@@ -132,7 +132,7 @@ void NodeGraph::add_bNode(const CompositorContext &context,
}
/* replace slow nodes with proxies for fast execution */
- if (context.isFastCalculation() && !Converter::is_fast_node(b_node)) {
+ if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) {
add_proxies_skip(b_ntree, b_node, key, is_active_group);
return;
}
@@ -146,7 +146,7 @@ void NodeGraph::add_bNode(const CompositorContext &context,
}
else {
/* regular nodes, handled in Converter */
- Node *node = Converter::convert(b_node);
+ Node *node = COM_convert_bnode(b_node);
if (node) {
add_node(node, b_ntree, key, is_active_group);
}
@@ -188,7 +188,8 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
if (!(b_nodelink->flag & NODE_LINK_VALID)) {
return;
}
- if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL)) {
+ if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL) ||
+ (b_nodelink->flag & NODE_LINK_MUTED)) {
return;
}
@@ -202,8 +203,7 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
}
NodeInputs inputs = find_inputs(node_range, b_nodelink->tosock);
- for (NodeInputs::const_iterator it = inputs.begin(); it != inputs.end(); ++it) {
- NodeInput *input = *it;
+ for (NodeInput *input : inputs) {
if (input->isLinked()) {
continue;
}
diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h
index 7252d546fce..990e3a30831 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.h
+++ b/source/blender/compositor/intern/COM_NodeGraph.h
@@ -18,6 +18,8 @@
#pragma once
+#include "BLI_vector.hh"
+
#include <map>
#include <set>
#include <vector>
@@ -39,33 +41,21 @@ class NodeOutput;
*/
class NodeGraph {
public:
- class Link {
- private:
- NodeOutput *m_from;
- NodeInput *m_to;
-
- public:
- Link(NodeOutput *from, NodeInput *to) : m_from(from), m_to(to)
- {
- }
+ struct Link {
+ NodeOutput *from;
+ NodeInput *to;
- NodeOutput *getFromSocket() const
- {
- return m_from;
- }
- NodeInput *getToSocket() const
+ Link(NodeOutput *from, NodeInput *to) : from(from), to(to)
{
- return m_to;
}
};
typedef std::vector<Node *> Nodes;
typedef Nodes::iterator NodeIterator;
- typedef std::vector<Link> Links;
private:
Nodes m_nodes;
- Links m_links;
+ blender::Vector<Link> m_links;
public:
NodeGraph();
@@ -75,7 +65,7 @@ class NodeGraph {
{
return m_nodes;
}
- const Links &links() const
+ const blender::Vector<Link> &links() const
{
return m_links;
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cc
index 1a30806f28c..0cc642479ac 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -151,8 +151,7 @@ NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex)
void NodeOperation::getConnectedInputSockets(Inputs *sockets)
{
- for (Inputs::const_iterator it = m_inputs.begin(); it != m_inputs.end(); ++it) {
- NodeOperationInput *input = *it;
+ for (NodeOperationInput *input : m_inputs) {
if (input->isConnected()) {
sockets->push_back(input);
}
@@ -182,10 +181,10 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
first = false;
}
else {
- output->xmin = min(output->xmin, tempOutput.xmin);
- output->ymin = min(output->ymin, tempOutput.ymin);
- output->xmax = max(output->xmax, tempOutput.xmax);
- output->ymax = max(output->ymax, tempOutput.ymax);
+ output->xmin = MIN2(output->xmin, tempOutput.xmin);
+ output->ymin = MIN2(output->ymin, tempOutput.ymin);
+ output->xmax = MAX2(output->xmax, tempOutput.xmax);
+ output->ymax = MAX2(output->ymax, tempOutput.ymax);
}
}
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 0ce7c1389bd..f26279e2869 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -33,10 +33,6 @@
#include "clew.h"
-using std::list;
-using std::max;
-using std::min;
-
class OpenCLDevice;
class ReadBufferOperation;
class WriteBufferOperation;
@@ -239,8 +235,8 @@ class NodeOperation : public SocketReader {
MemoryBuffer * /*outputMemoryBuffer*/,
cl_mem /*clOutputBuffer*/,
MemoryBuffer ** /*inputMemoryBuffers*/,
- list<cl_mem> * /*clMemToCleanUp*/,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> * /*clMemToCleanUp*/,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
}
virtual void deinitExecution();
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 35a3314db3b..b6da1e128c5 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -16,6 +16,7 @@
* Copyright 2013, Blender Foundation.
*/
+#include "BLI_multi_value_map.hh"
#include "BLI_utildefines.h"
#include "COM_Converter.h"
@@ -67,20 +68,19 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
* Inverting yields a map of node inputs to all connected operation inputs,
* so multiple operations can use the same node input.
*/
- OpInputInverseMap inverse_input_map;
- for (InputSocketMap::const_iterator it = m_input_map.begin(); it != m_input_map.end(); ++it) {
- inverse_input_map[it->second].push_back(it->first);
+ blender::MultiValueMap<NodeInput *, NodeOperationInput *> inverse_input_map;
+ for (blender::Map<NodeOperationInput *, NodeInput *>::MutableItem item : m_input_map.items()) {
+ inverse_input_map.add(item.value, item.key);
}
- for (NodeGraph::Links::const_iterator it = m_graph.links().begin(); it != m_graph.links().end();
- ++it) {
- const NodeGraph::Link &link = *it;
- NodeOutput *from = link.getFromSocket();
- NodeInput *to = link.getToSocket();
+ for (const NodeGraph::Link &link : m_graph.links()) {
+ NodeOutput *from = link.from;
+ NodeInput *to = link.to;
- NodeOperationOutput *op_from = find_operation_output(m_output_map, from);
- const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to);
- if (!op_from || op_to_list.empty()) {
+ NodeOperationOutput *op_from = m_output_map.lookup_default(from, nullptr);
+
+ const blender::Span<NodeOperationInput *> op_to_list = inverse_input_map.lookup(to);
+ if (!op_from || op_to_list.is_empty()) {
/* XXX allow this? error/debug message? */
// BLI_assert(false);
/* XXX note: this can happen with certain nodes (e.g. OutputFile)
@@ -90,8 +90,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
continue;
}
- for (OpInputs::const_iterator it = op_to_list.begin(); it != op_to_list.end(); ++it) {
- NodeOperationInput *op_to = *it;
+ for (NodeOperationInput *op_to : op_to_list) {
addLink(op_from, op_to);
}
}
@@ -125,7 +124,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
void NodeOperationBuilder::addOperation(NodeOperation *operation)
{
- m_operations.push_back(operation);
+ m_operations.append(operation);
}
void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket,
@@ -138,7 +137,7 @@ void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket,
* for resolving links the map will be inverted first in convertToOperations,
* to get a list of links for each node input socket.
*/
- m_input_map[operation_socket] = node_socket;
+ m_input_map.add_new(operation_socket, node_socket);
}
void NodeOperationBuilder::mapOutputSocket(NodeOutput *node_socket,
@@ -147,7 +146,7 @@ void NodeOperationBuilder::mapOutputSocket(NodeOutput *node_socket,
BLI_assert(m_current_node);
BLI_assert(node_socket->getNode() == m_current_node);
- m_output_map[node_socket] = operation_socket;
+ m_output_map.add_new(node_socket, operation_socket);
}
void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput *to)
@@ -156,7 +155,7 @@ void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput
return;
}
- m_links.push_back(Link(from, to));
+ m_links.append(Link(from, to));
/* register with the input */
to->setLink(from);
@@ -164,40 +163,19 @@ void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput
void NodeOperationBuilder::removeInputLink(NodeOperationInput *to)
{
- for (Links::iterator it = m_links.begin(); it != m_links.end(); ++it) {
- Link &link = *it;
+ int index = 0;
+ for (Link &link : m_links) {
if (link.to() == to) {
/* unregister with the input */
to->setLink(nullptr);
- m_links.erase(it);
+ m_links.remove(index);
return;
}
+ index++;
}
}
-NodeInput *NodeOperationBuilder::find_node_input(const InputSocketMap &map,
- NodeOperationInput *op_input)
-{
- InputSocketMap::const_iterator it = map.find(op_input);
- return (it != map.end() ? it->second : NULL);
-}
-
-const NodeOperationBuilder::OpInputs &NodeOperationBuilder::find_operation_inputs(
- const OpInputInverseMap &map, NodeInput *node_input)
-{
- static const OpInputs empty_list;
- OpInputInverseMap::const_iterator it = map.find(node_input);
- return (it != map.end() ? it->second : empty_list);
-}
-
-NodeOperationOutput *NodeOperationBuilder::find_operation_output(const OutputSocketMap &map,
- NodeOutput *node_output)
-{
- OutputSocketMap::const_iterator it = map.find(node_output);
- return (it != map.end() ? it->second : NULL);
-}
-
PreviewOperation *NodeOperationBuilder::make_preview_operation() const
{
BLI_assert(m_current_node);
@@ -271,10 +249,8 @@ void NodeOperationBuilder::registerViewer(ViewerOperation *viewer)
void NodeOperationBuilder::add_datatype_conversions()
{
- Links convert_links;
- for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
- const Link &link = *it;
-
+ blender::Vector<Link> convert_links;
+ for (const Link &link : m_links) {
/* proxy operations can skip data type conversion */
NodeOperation *from_op = &link.from()->getOperation();
NodeOperation *to_op = &link.to()->getOperation();
@@ -283,12 +259,11 @@ void NodeOperationBuilder::add_datatype_conversions()
}
if (link.from()->getDataType() != link.to()->getDataType()) {
- convert_links.push_back(link);
+ convert_links.append(link);
}
}
- for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) {
- const Link &link = *it;
- NodeOperation *converter = Converter::convertDataType(link.from(), link.to());
+ for (const Link &link : convert_links) {
+ NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to());
if (converter) {
addOperation(converter);
@@ -306,8 +281,7 @@ void NodeOperationBuilder::add_operation_input_constants()
*/
using Inputs = std::vector<NodeOperationInput *>;
Inputs pending_inputs;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
+ for (NodeOperation *op : m_operations) {
for (int k = 0; k < op->getNumberOfInputSockets(); ++k) {
NodeOperationInput *input = op->getInputSocket(k);
if (!input->isConnected()) {
@@ -317,7 +291,7 @@ void NodeOperationBuilder::add_operation_input_constants()
}
for (Inputs::const_iterator it = pending_inputs.begin(); it != pending_inputs.end(); ++it) {
NodeOperationInput *input = *it;
- add_input_constant_value(input, find_node_input(m_input_map, input));
+ add_input_constant_value(input, m_input_map.lookup(input));
}
}
@@ -375,19 +349,16 @@ void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input,
void NodeOperationBuilder::resolve_proxies()
{
- Links proxy_links;
- for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
- const Link &link = *it;
+ blender::Vector<Link> proxy_links;
+ for (const Link &link : m_links) {
/* don't replace links from proxy to proxy, since we may need them for replacing others! */
if (link.from()->getOperation().isProxyOperation() &&
!link.to()->getOperation().isProxyOperation()) {
- proxy_links.push_back(link);
+ proxy_links.append(link);
}
}
- for (Links::const_iterator it = proxy_links.begin(); it != proxy_links.end(); ++it) {
- const Link &link = *it;
-
+ for (const Link &link : proxy_links) {
NodeOperationInput *to = link.to();
NodeOperationOutput *from = link.from();
do {
@@ -408,9 +379,7 @@ void NodeOperationBuilder::resolve_proxies()
void NodeOperationBuilder::determineResolutions()
{
/* determine all resolutions of the operations (Width/Height) */
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) {
unsigned int resolution[2] = {0, 0};
unsigned int preferredResolution[2] = {0, 0};
@@ -419,9 +388,7 @@ void NodeOperationBuilder::determineResolutions()
}
}
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) {
unsigned int resolution[2] = {0, 0};
unsigned int preferredResolution[2] = {0, 0};
@@ -432,33 +399,29 @@ void NodeOperationBuilder::determineResolutions()
/* add convert resolution operations when needed */
{
- Links convert_links;
- for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
- const Link &link = *it;
-
+ blender::Vector<Link> convert_links;
+ for (const Link &link : m_links) {
if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) {
NodeOperation &from_op = link.from()->getOperation();
NodeOperation &to_op = link.to()->getOperation();
if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) {
- convert_links.push_back(link);
+ convert_links.append(link);
}
}
}
- for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) {
- const Link &link = *it;
- Converter::convertResolution(*this, link.from(), link.to());
+ for (const Link &link : convert_links) {
+ COM_convert_resolution(*this, link.from(), link.to());
}
}
}
-NodeOperationBuilder::OpInputs NodeOperationBuilder::cache_output_links(
+blender::Vector<NodeOperationInput *> NodeOperationBuilder::cache_output_links(
NodeOperationOutput *output) const
{
- OpInputs inputs;
- for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
- const Link &link = *it;
+ blender::Vector<NodeOperationInput *> inputs;
+ for (const Link &link : m_links) {
if (link.from() == output) {
- inputs.push_back(link.to());
+ inputs.append(link.to());
}
}
return inputs;
@@ -467,8 +430,7 @@ NodeOperationBuilder::OpInputs NodeOperationBuilder::cache_output_links(
WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation(
NodeOperationOutput *output) const
{
- for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
- const Link &link = *it;
+ for (const Link &link : m_links) {
if (link.from() == output) {
NodeOperation &op = link.to()->getOperation();
if (op.isWriteBufferOperation()) {
@@ -521,15 +483,13 @@ void NodeOperationBuilder::add_output_buffers(NodeOperation *operation,
NodeOperationOutput *output)
{
/* cache connected sockets, so we can safely remove links first before replacing them */
- OpInputs targets = cache_output_links(output);
- if (targets.empty()) {
+ blender::Vector<NodeOperationInput *> targets = cache_output_links(output);
+ if (targets.is_empty()) {
return;
}
WriteBufferOperation *writeOperation = nullptr;
- for (OpInputs::const_iterator it = targets.begin(); it != targets.end(); ++it) {
- NodeOperationInput *target = *it;
-
+ for (NodeOperationInput *target : targets) {
/* try to find existing write buffer operation */
if (target->getOperation().isWriteBufferOperation()) {
BLI_assert(writeOperation == nullptr); /* there should only be one write op connected */
@@ -553,8 +513,7 @@ void NodeOperationBuilder::add_output_buffers(NodeOperation *operation,
writeOperation->readResolutionFromInputSocket();
/* add readbuffer op for every former connected input */
- for (OpInputs::const_iterator it = targets.begin(); it != targets.end(); ++it) {
- NodeOperationInput *target = *it;
+ for (NodeOperationInput *target : targets) {
if (&target->getOperation() == writeOperation) {
continue; /* skip existing write op links */
}
@@ -575,16 +534,14 @@ void NodeOperationBuilder::add_complex_operation_buffers()
/* note: complex ops and get cached here first, since adding operations
* will invalidate iterators over the main m_operations
*/
- Operations complex_ops;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- if ((*it)->isComplex()) {
- complex_ops.push_back(*it);
+ blender::Vector<NodeOperation *> complex_ops;
+ for (NodeOperation *operation : m_operations) {
+ if (operation->isComplex()) {
+ complex_ops.append(operation);
}
}
- for (Operations::const_iterator it = complex_ops.begin(); it != complex_ops.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : complex_ops) {
DebugInfo::operation_read_write_buffer(op);
for (int index = 0; index < op->getNumberOfInputSockets(); index++) {
@@ -624,9 +581,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *
void NodeOperationBuilder::prune_operations()
{
Tags reachable;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
/* output operations are primary executed operations */
if (op->isOutputOperation(m_context->isRendering())) {
find_reachable_operations_recursive(reachable, op);
@@ -634,12 +589,10 @@ void NodeOperationBuilder::prune_operations()
}
/* delete unreachable operations */
- Operations reachable_ops;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ blender::Vector<NodeOperation *> reachable_ops;
+ for (NodeOperation *op : m_operations) {
if (reachable.find(op) != reachable.end()) {
- reachable_ops.push_back(op);
+ reachable_ops.append(op);
}
else {
delete op;
@@ -650,7 +603,7 @@ void NodeOperationBuilder::prune_operations()
}
/* topological (depth-first) sorting of operations */
-static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted,
+static void sort_operations_recursive(blender::Vector<NodeOperation *> &sorted,
Tags &visited,
NodeOperation *op)
{
@@ -666,17 +619,17 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted,
}
}
- sorted.push_back(op);
+ sorted.append(op);
}
void NodeOperationBuilder::sort_operations()
{
- Operations sorted;
+ blender::Vector<NodeOperation *> sorted;
sorted.reserve(m_operations.size());
Tags visited;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- sort_operations_recursive(sorted, visited, *it);
+ for (NodeOperation *operation : m_operations) {
+ sort_operations_recursive(sorted, visited, operation);
}
m_operations = sorted;
@@ -705,7 +658,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe
ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
{
ExecutionGroup *group = new ExecutionGroup();
- m_groups.push_back(group);
+ m_groups.append(group);
Tags visited;
add_group_operations_recursive(visited, op, group);
@@ -715,9 +668,7 @@ ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
void NodeOperationBuilder::group_operations()
{
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering())) {
ExecutionGroup *group = make_group(op);
group->setOutputExecutionGroup(true);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index 5dd4022b127..5d497e8ec7d 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -24,8 +24,6 @@
#include "COM_NodeGraph.h"
-using std::vector;
-
class CompositorContext;
class Node;
@@ -64,28 +62,18 @@ class NodeOperationBuilder {
}
};
- typedef std::vector<NodeOperation *> Operations;
- typedef std::vector<Link> Links;
- typedef std::vector<ExecutionGroup *> Groups;
-
- typedef std::map<NodeOperationInput *, NodeInput *> InputSocketMap;
- typedef std::map<NodeOutput *, NodeOperationOutput *> OutputSocketMap;
-
- typedef std::vector<NodeOperationInput *> OpInputs;
- typedef std::map<NodeInput *, OpInputs> OpInputInverseMap;
-
private:
const CompositorContext *m_context;
NodeGraph m_graph;
- Operations m_operations;
- Links m_links;
- Groups m_groups;
+ blender::Vector<NodeOperation *> m_operations;
+ blender::Vector<Link> m_links;
+ blender::Vector<ExecutionGroup *> m_groups;
/** Maps operation inputs to node inputs */
- InputSocketMap m_input_map;
+ blender::Map<NodeOperationInput *, NodeInput *> m_input_map;
/** Maps node outputs to operation outputs */
- OutputSocketMap m_output_map;
+ blender::Map<NodeOutput *, NodeOperationOutput *> m_output_map;
Node *m_current_node;
@@ -130,12 +118,6 @@ class NodeOperationBuilder {
}
protected:
- static NodeInput *find_node_input(const InputSocketMap &map, NodeOperationInput *op_input);
- static const OpInputs &find_operation_inputs(const OpInputInverseMap &map,
- NodeInput *node_input);
- static NodeOperationOutput *find_operation_output(const OutputSocketMap &map,
- NodeOutput *node_output);
-
/** Add datatype conversion where needed */
void add_datatype_conversions();
@@ -150,7 +132,7 @@ class NodeOperationBuilder {
void determineResolutions();
/** Helper function to store connected inputs for replacement */
- OpInputs cache_output_links(NodeOperationOutput *output) const;
+ blender::Vector<NodeOperationInput *> cache_output_links(NodeOperationOutput *output) const;
/** Find a connected write buffer operation to an OpOutput */
WriteBufferOperation *find_attached_write_buffer_operation(NodeOperationOutput *output) const;
/** Add read/write buffer operations around complex operations */
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cc
index acfe800e433..34450366aec 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cc
@@ -61,8 +61,8 @@ void OpenCLDevice::deinitialize()
void OpenCLDevice::execute(WorkPackage *work)
{
- const unsigned int chunkNumber = work->getChunkNumber();
- ExecutionGroup *executionGroup = work->getExecutionGroup();
+ const unsigned int chunkNumber = work->chunk_number;
+ ExecutionGroup *executionGroup = work->execution_group;
rcti rect;
executionGroup->determineChunkRect(&rect, chunkNumber);
@@ -79,7 +79,7 @@ void OpenCLDevice::execute(WorkPackage *work)
cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
SocketReader *reader)
{
@@ -111,7 +111,7 @@ const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBu
cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
ReadBufferOperation *reader)
{
@@ -258,7 +258,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel,
}
cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname,
- list<cl_kernel> *clKernelsToCleanUp)
+ std::list<cl_kernel> *clKernelsToCleanUp)
{
cl_int error;
cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error);
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index d502f5aa34b..e4fd397b4e8 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -25,8 +25,6 @@ class OpenCLDevice;
#include "COM_WorkScheduler.h"
#include "clew.h"
-using std::list;
-
/**
* \brief device representing an GPU OpenCL device.
* an instance of this class represents a single cl_device
@@ -107,13 +105,13 @@ class OpenCLDevice : public Device {
cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
SocketReader *reader);
cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
ReadBufferOperation *reader);
void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel,
@@ -130,5 +128,5 @@ class OpenCLDevice : public Device {
MemoryBuffer *outputMemoryBuffer,
int offsetIndex,
NodeOperation *operation);
- cl_kernel COM_clCreateKernel(const char *kernelname, list<cl_kernel> *clKernelsToCleanUp);
+ cl_kernel COM_clCreateKernel(const char *kernelname, std::list<cl_kernel> *clKernelsToCleanUp);
};
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
index 5febf3802de..5febf3802de 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.h b/source/blender/compositor/intern/COM_SingleThreadedOperation.h
index 31597c31bf7..32f4515cf2a 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.h
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.h
@@ -27,7 +27,7 @@ class SingleThreadedOperation : public NodeOperation {
protected:
inline bool isCached()
{
- return this->m_cachedInstance != NULL;
+ return this->m_cachedInstance != nullptr;
}
public:
diff --git a/source/blender/compositor/intern/COM_SocketReader.cpp b/source/blender/compositor/intern/COM_SocketReader.cc
index 93c8a143b86..93c8a143b86 100644
--- a/source/blender/compositor/intern/COM_SocketReader.cpp
+++ b/source/blender/compositor/intern/COM_SocketReader.cc
diff --git a/source/blender/compositor/intern/COM_WorkPackage.cpp b/source/blender/compositor/intern/COM_WorkPackage.cc
index 795f8d88d50..60684f2c45c 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.cpp
+++ b/source/blender/compositor/intern/COM_WorkPackage.cc
@@ -18,8 +18,8 @@
#include "COM_WorkPackage.h"
-WorkPackage::WorkPackage(ExecutionGroup *group, unsigned int chunkNumber)
+WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number)
{
- this->m_executionGroup = group;
- this->m_chunkNumber = chunkNumber;
+ this->execution_group = execution_group;
+ this->chunk_number = chunk_number;
}
diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h
index f4370aa41be..db5eb3d3072 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.h
+++ b/source/blender/compositor/intern/COM_WorkPackage.h
@@ -16,8 +16,6 @@
* Copyright 2011, Blender Foundation.
*/
-class WorkPackage;
-
#pragma once
class ExecutionGroup;
@@ -27,41 +25,23 @@ class ExecutionGroup;
* \brief contains data about work that can be scheduled
* \see WorkScheduler
*/
-class WorkPackage {
- private:
+struct WorkPackage {
/**
* \brief executionGroup with the operations-setup to be evaluated
*/
- ExecutionGroup *m_executionGroup;
+ ExecutionGroup *execution_group;
/**
* \brief number of the chunk to be executed
*/
- unsigned int m_chunkNumber;
+ unsigned int chunk_number;
- public:
/**
* constructor
* \param group: the ExecutionGroup
- * \param chunkNumber: the number of the chunk
- */
- WorkPackage(ExecutionGroup *group, unsigned int chunkNumber);
-
- /**
- * \brief get the ExecutionGroup
- */
- ExecutionGroup *getExecutionGroup() const
- {
- return this->m_executionGroup;
- }
-
- /**
- * \brief get the number of the chunk
+ * \param chunk_number: the number of the chunk
*/
- unsigned int getChunkNumber() const
- {
- return this->m_chunkNumber;
- }
+ WorkPackage(ExecutionGroup *group, unsigned int chunk_number);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage")
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cc
index 9ca704afdea..f19c54991cd 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cc
@@ -48,7 +48,7 @@ static ThreadLocal(CPUDevice *) g_thread_device;
static struct {
/** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
*/
- vector<CPUDevice *> cpu_devices;
+ std::vector<CPUDevice *> cpu_devices;
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
/** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */
@@ -62,7 +62,7 @@ static struct {
cl_program opencl_program;
/** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is
* created. */
- vector<OpenCLDevice *> gpu_devices;
+ std::vector<OpenCLDevice *> gpu_devices;
/** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */
ListBase gpu_threads;
/** \brief all scheduled work for the GPU. */
@@ -190,10 +190,10 @@ bool WorkScheduler::has_gpu_devices()
# ifdef COM_OPENCL_ENABLED
return !g_work_scheduler.gpu_devices.empty();
# else
- return 0;
+ return false;
# endif
#else
- return 0;
+ return false;
#endif
}
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cc
index 68e4f80f91f..68e4f80f91f 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cc
diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cc
index 640fbf49808..640fbf49808 100644
--- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
+++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cc
diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
index e8037f923f2..e8037f923f2 100644
--- a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_BlurNode.cpp b/source/blender/compositor/nodes/COM_BlurNode.cc
index b82bede8443..b82bede8443 100644
--- a/source/blender/compositor/nodes/COM_BlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp b/source/blender/compositor/nodes/COM_BokehBlurNode.cc
index 5096dbef608..5096dbef608 100644
--- a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cpp b/source/blender/compositor/nodes/COM_BokehImageNode.cc
index 87fe4979c1d..87fe4979c1d 100644
--- a/source/blender/compositor/nodes/COM_BokehImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehImageNode.cc
diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp b/source/blender/compositor/nodes/COM_BoxMaskNode.cc
index fe59bd32939..fe59bd32939 100644
--- a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cc
index fcd2a6de1f4..fcd2a6de1f4 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cc
diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
index 598cd7b7745..598cd7b7745 100644
--- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
index 83e88b35f92..83e88b35f92 100644
--- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
index 596d9631297..596d9631297 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
index 92b334fddb9..92b334fddb9 100644
--- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp b/source/blender/compositor/nodes/COM_ColorCurveNode.cc
index e1888f3f0bc..e1888f3f0bc 100644
--- a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp b/source/blender/compositor/nodes/COM_ColorExposureNode.cc
index cd0285ac373..cd0285ac373 100644
--- a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cc
index 865eee5427f..865eee5427f 100644
--- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorNode.cpp b/source/blender/compositor/nodes/COM_ColorNode.cc
index e6f8bfa01fe..e6f8bfa01fe 100644
--- a/source/blender/compositor/nodes/COM_ColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cc
index 1504a76cee7..1504a76cee7 100644
--- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorRampNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp b/source/blender/compositor/nodes/COM_ColorSpillNode.cc
index d1a3099e998..d1a3099e998 100644
--- a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cc
index 4115bad5d3f..4115bad5d3f 100644
--- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cc
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cpp b/source/blender/compositor/nodes/COM_CombineColorNode.cc
index 12968f06a10..12968f06a10 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cc
index 32ac1fccec9..32ac1fccec9 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CompositorNode.cc
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
index 2921b44c95b..2921b44c95b 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cc
index efe847bbfbf..efe847bbfbf 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cc
diff --git a/source/blender/compositor/nodes/COM_CropNode.cpp b/source/blender/compositor/nodes/COM_CropNode.cc
index 0f0883b0151..0f0883b0151 100644
--- a/source/blender/compositor/nodes/COM_CropNode.cpp
+++ b/source/blender/compositor/nodes/COM_CropNode.cc
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
new file mode 100644
index 00000000000..4c698b5609f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -0,0 +1,263 @@
+/*
+ * 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 2018, Blender Foundation.
+ */
+
+#include "COM_CryptomatteNode.h"
+#include "BKE_node.h"
+#include "BLI_assert.h"
+#include "BLI_hash_mm3.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "COM_ConvertOperation.h"
+#include "COM_CryptomatteOperation.h"
+#include "COM_MultilayerImageOperation.h"
+#include "COM_RenderLayersProg.h"
+#include "COM_SetAlphaMultiplyOperation.h"
+#include "COM_SetColorOperation.h"
+#include <iterator>
+#include <string>
+
+/** \name Cryptomatte base
+ * \{ */
+
+void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeOutput *output_image_socket = this->getOutputSocket(0);
+
+ bNode *node = this->getbNode();
+ NodeCryptomatte *cryptomatte_settings = static_cast<NodeCryptomatte *>(node->storage);
+
+ CryptomatteOperation *cryptomatte_operation = create_cryptomatte_operation(
+ converter, context, *node, cryptomatte_settings);
+ converter.addOperation(cryptomatte_operation);
+
+ NodeOutput *output_matte_socket = this->getOutputSocket(1);
+ SeparateChannelOperation *extract_mask_operation = new SeparateChannelOperation;
+ extract_mask_operation->setChannel(3);
+ converter.addOperation(extract_mask_operation);
+ converter.addLink(cryptomatte_operation->getOutputSocket(0),
+ extract_mask_operation->getInputSocket(0));
+ converter.mapOutputSocket(output_matte_socket, extract_mask_operation->getOutputSocket(0));
+
+ NodeInput *input_image_socket = this->getInputSocket(0);
+ SetAlphaMultiplyOperation *apply_mask_operation = new SetAlphaMultiplyOperation();
+ converter.mapInputSocket(input_image_socket, apply_mask_operation->getInputSocket(0));
+ converter.addOperation(apply_mask_operation);
+ converter.addLink(extract_mask_operation->getOutputSocket(0),
+ apply_mask_operation->getInputSocket(1));
+ converter.mapOutputSocket(output_image_socket, apply_mask_operation->getOutputSocket(0));
+
+ NodeOutput *output_pick_socket = this->getOutputSocket(2);
+ SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation();
+ converter.addOperation(extract_pick_operation);
+ converter.addInputValue(extract_pick_operation->getInputSocket(1), 1.0f);
+ converter.addLink(cryptomatte_operation->getOutputSocket(0),
+ extract_pick_operation->getInputSocket(0));
+ converter.mapOutputSocket(output_pick_socket, extract_pick_operation->getOutputSocket(0));
+}
+
+/* \} */
+
+/** \name Cryptomatte V2
+ * \{ */
+static std::string prefix_from_node(const bNode &node)
+{
+ char prefix[MAX_NAME];
+ ntreeCompositCryptomatteLayerPrefix(&node, prefix, sizeof(prefix));
+ return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix)));
+}
+
+static std::string combined_layer_pass_name(RenderLayer *render_layer, RenderPass *render_pass)
+{
+ if (render_layer->name[0] == '\0') {
+ return std::string(render_pass->name,
+ BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
+ }
+
+ std::string combined_name =
+ blender::StringRef(render_layer->name,
+ BLI_strnlen(render_layer->name, sizeof(render_layer->name))) +
+ "." +
+ blender::StringRef(render_pass->name,
+ BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
+ return combined_name;
+}
+
+void CryptomatteNode::input_operations_from_render_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations)
+{
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return;
+ }
+
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *render = RE_GetSceneRender(scene);
+ RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
+
+ if (!render_result) {
+ return;
+ }
+
+ const short cryptomatte_layer_id = 0;
+ const std::string prefix = prefix_from_node(node);
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ if (render_layer) {
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
+ if (blender::StringRef(combined_name).startswith(prefix)) {
+ RenderLayersProg *op = new RenderLayersProg(
+ render_pass->name, COM_DT_COLOR, render_pass->channels);
+ op->setScene(scene);
+ op->setLayerId(cryptomatte_layer_id);
+ op->setRenderData(context.getRenderData());
+ op->setViewName(context.getViewName());
+ r_input_operations.append(op);
+ }
+ }
+ }
+ }
+ RE_ReleaseResult(render);
+}
+
+void CryptomatteNode::input_operations_from_image_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations)
+{
+ NodeCryptomatte *cryptomatte_settings = (NodeCryptomatte *)node.storage;
+ Image *image = (Image *)node.id;
+ if (!image) {
+ return;
+ }
+
+ BLI_assert(GS(image->id.name) == ID_IM);
+ if (image->type != IMA_TYPE_MULTILAYER) {
+ return;
+ }
+
+ ImageUser *iuser = &cryptomatte_settings->iuser;
+ BKE_image_user_frame_calc(image, iuser, context.getFramenumber());
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
+
+ if (image->rr) {
+ int view = 0;
+ if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
+ if (iuser->view == 0) {
+ /* Heuristic to match image name with scene names, check if the view name exists in the
+ * image. */
+ view = BLI_findstringindex(
+ &image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ if (view == -1) {
+ view = 0;
+ }
+ }
+ else {
+ view = iuser->view - 1;
+ }
+ }
+
+ const std::string prefix = prefix_from_node(node);
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
+ if (blender::StringRef(combined_name).startswith(prefix)) {
+ MultilayerColorOperation *op = new MultilayerColorOperation(
+ render_layer, render_pass, view);
+ op->setImage(image);
+ op->setImageUser(iuser);
+ op->setFramenumber(context.getFramenumber());
+ r_input_operations.append(op);
+ }
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+}
+
+blender::Vector<NodeOperation *> CryptomatteNode::create_input_operations(
+ const CompositorContext &context, const bNode &node)
+{
+ blender::Vector<NodeOperation *> input_operations;
+ switch (node.custom1) {
+ case CMP_CRYPTOMATTE_SRC_RENDER:
+ input_operations_from_render_source(context, node, input_operations);
+ break;
+ case CMP_CRYPTOMATTE_SRC_IMAGE:
+ input_operations_from_image_source(context, node, input_operations);
+ break;
+ }
+
+ if (input_operations.is_empty()) {
+ SetColorOperation *op = new SetColorOperation();
+ op->setChannel1(0.0f);
+ op->setChannel2(1.0f);
+ op->setChannel3(0.0f);
+ op->setChannel4(0.0f);
+ input_operations.append(op);
+ }
+ return input_operations;
+}
+CryptomatteOperation *CryptomatteNode::create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const
+{
+ blender::Vector<NodeOperation *> input_operations = create_input_operations(context, node);
+ CryptomatteOperation *operation = new CryptomatteOperation(input_operations.size());
+ LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
+ operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ }
+ for (int i = 0; i < input_operations.size(); ++i) {
+ converter.addOperation(input_operations[i]);
+ converter.addLink(input_operations[i]->getOutputSocket(), operation->getInputSocket(i));
+ }
+ return operation;
+}
+
+/* \} */
+
+/** \name Cryptomatte legacy
+ * \{ */
+
+CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &UNUSED(context),
+ const bNode &UNUSED(node),
+ const NodeCryptomatte *cryptomatte_settings) const
+{
+ const int num_inputs = getNumberOfInputSockets() - 1;
+ CryptomatteOperation *operation = new CryptomatteOperation(num_inputs);
+ if (cryptomatte_settings) {
+ LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
+ operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ }
+ }
+
+ for (int i = 0; i < num_inputs; i++) {
+ converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ }
+
+ return operation;
+}
+
+/* \} */ \ No newline at end of file
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
deleted file mode 100644
index 27ef98af8f3..00000000000
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2018, Blender Foundation.
- */
-
-#include "COM_CryptomatteNode.h"
-#include "COM_ConvertOperation.h"
-#include "COM_CryptomatteOperation.h"
-
-#include "BLI_assert.h"
-#include "BLI_hash_mm3.h"
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-
-#include "COM_SetAlphaMultiplyOperation.h"
-#include <iterator>
-
-CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
-{
- /* pass */
-}
-
-void CryptomatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
-{
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
- NodeOutput *outputSocketPick = this->getOutputSocket(2);
-
- bNode *node = this->getbNode();
- NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage;
-
- CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1);
- if (cryptoMatteSettings) {
- LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) {
- operation->addObjectIndex(cryptomatte_entry->encoded_hash);
- }
- }
-
- converter.addOperation(operation);
-
- for (int i = 0; i < getNumberOfInputSockets() - 1; i++) {
- converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
- }
-
- SeparateChannelOperation *separateOperation = new SeparateChannelOperation;
- separateOperation->setChannel(3);
- converter.addOperation(separateOperation);
-
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
-
- converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0));
- converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1));
-
- SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation();
- converter.addOperation(clearAlphaOperation);
- converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f);
-
- converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0));
-
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
- converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0));
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0));
- converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0));
-}
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h
index 1fb8893efa0..e99a104c914 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.h
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h
@@ -18,14 +18,72 @@
#pragma once
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "COM_CryptomatteOperation.h"
#include "COM_Node.h"
/**
* \brief CryptomatteNode
* \ingroup Node
*/
-class CryptomatteNode : public Node {
+class CryptomatteBaseNode : public Node {
+ protected:
+ CryptomatteBaseNode(bNode *editor_node) : Node(editor_node)
+ {
+ /* pass */
+ }
+
public:
- CryptomatteNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+
+ protected:
+ virtual CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const = 0;
+};
+
+class CryptomatteNode : public CryptomatteBaseNode {
+ public:
+ CryptomatteNode(bNode *editor_node) : CryptomatteBaseNode(editor_node)
+ {
+ /* pass */
+ }
+
+ protected:
+ CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const override;
+
+ private:
+ static blender::Vector<NodeOperation *> create_input_operations(const CompositorContext &context,
+ const bNode &node);
+ static void input_operations_from_render_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations);
+ static void input_operations_from_image_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations);
+};
+
+class CryptomatteLegacyNode : public CryptomatteBaseNode {
+ public:
+ CryptomatteLegacyNode(bNode *editor_node) : CryptomatteBaseNode(editor_node)
+ {
+ /* pass */
+ }
+
+ protected:
+ CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const override;
};
diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cpp b/source/blender/compositor/nodes/COM_DefocusNode.cc
index 393b1f2dabb..393b1f2dabb 100644
--- a/source/blender/compositor/nodes/COM_DefocusNode.cpp
+++ b/source/blender/compositor/nodes/COM_DefocusNode.cc
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cc
index 1aae81e1e7b..1aae81e1e7b 100644
--- a/source/blender/compositor/nodes/COM_DenoiseNode.cpp
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.cc
diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cpp b/source/blender/compositor/nodes/COM_DespeckleNode.cc
index 58734917831..58734917831 100644
--- a/source/blender/compositor/nodes/COM_DespeckleNode.cpp
+++ b/source/blender/compositor/nodes/COM_DespeckleNode.cc
diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
index 3d538e9b4a0..3d538e9b4a0 100644
--- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
index e90707618e5..e90707618e5 100644
--- a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp
+++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
index f8d0eaf4675..f8d0eaf4675 100644
--- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cpp b/source/blender/compositor/nodes/COM_DisplaceNode.cc
index 0c0c3aad646..0c0c3aad646 100644
--- a/source/blender/compositor/nodes/COM_DisplaceNode.cpp
+++ b/source/blender/compositor/nodes/COM_DisplaceNode.cc
diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
index 37aeb5c8504..37aeb5c8504 100644
--- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
index 907a9f49353..907a9f49353 100644
--- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
index 1ae855c0f1d..1ae855c0f1d 100644
--- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cc
index 1147c11794f..1147c11794f 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cpp
+++ b/source/blender/compositor/nodes/COM_FilterNode.cc
diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cc
index d89e6b7b844..d89e6b7b844 100644
--- a/source/blender/compositor/nodes/COM_FlipNode.cpp
+++ b/source/blender/compositor/nodes/COM_FlipNode.cc
diff --git a/source/blender/compositor/nodes/COM_GammaNode.cpp b/source/blender/compositor/nodes/COM_GammaNode.cc
index 1ce17faa0dc..1ce17faa0dc 100644
--- a/source/blender/compositor/nodes/COM_GammaNode.cpp
+++ b/source/blender/compositor/nodes/COM_GammaNode.cc
diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cc
index ef088e42205..ef088e42205 100644
--- a/source/blender/compositor/nodes/COM_GlareNode.cpp
+++ b/source/blender/compositor/nodes/COM_GlareNode.cc
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
index 00125ba2ea5..00125ba2ea5 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
index dc2e5187e8f..dc2e5187e8f 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cpp b/source/blender/compositor/nodes/COM_IDMaskNode.cc
index 5ba54d75bcd..5ba54d75bcd 100644
--- a/source/blender/compositor/nodes/COM_IDMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_IDMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cc
index 69729e018d7..69729e018d7 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cc
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index e2053cfd3b8..b99fc07f105 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -33,7 +33,7 @@
class ImageNode : public Node {
private:
NodeOperation *doMultilayerCheck(NodeConverter &converter,
- RenderLayer *rl,
+ RenderLayer *render_layer,
RenderPass *render_pass,
Image *image,
ImageUser *user,
diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cpp b/source/blender/compositor/nodes/COM_InpaintNode.cc
index 40fe63ec9f3..40fe63ec9f3 100644
--- a/source/blender/compositor/nodes/COM_InpaintNode.cpp
+++ b/source/blender/compositor/nodes/COM_InpaintNode.cc
diff --git a/source/blender/compositor/nodes/COM_InvertNode.cpp b/source/blender/compositor/nodes/COM_InvertNode.cc
index 913452c42c8..913452c42c8 100644
--- a/source/blender/compositor/nodes/COM_InvertNode.cpp
+++ b/source/blender/compositor/nodes/COM_InvertNode.cc
diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cpp b/source/blender/compositor/nodes/COM_KeyingNode.cc
index 9b493d3f332..9b493d3f332 100644
--- a/source/blender/compositor/nodes/COM_KeyingNode.cpp
+++ b/source/blender/compositor/nodes/COM_KeyingNode.cc
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
index 93a9a071226..93a9a071226 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp b/source/blender/compositor/nodes/COM_LensDistortionNode.cc
index 34d2fba6433..34d2fba6433 100644
--- a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
+++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cc
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
index 8bfea1eff49..8bfea1eff49 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cpp b/source/blender/compositor/nodes/COM_MapRangeNode.cc
index 352bc0dd48d..352bc0dd48d 100644
--- a/source/blender/compositor/nodes/COM_MapRangeNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapRangeNode.cc
diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cpp b/source/blender/compositor/nodes/COM_MapUVNode.cc
index feb9c75ec56..feb9c75ec56 100644
--- a/source/blender/compositor/nodes/COM_MapUVNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapUVNode.cc
diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cpp b/source/blender/compositor/nodes/COM_MapValueNode.cc
index e07df8ad367..e07df8ad367 100644
--- a/source/blender/compositor/nodes/COM_MapValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapValueNode.cc
diff --git a/source/blender/compositor/nodes/COM_MaskNode.cpp b/source/blender/compositor/nodes/COM_MaskNode.cc
index a6415a3992e..a6415a3992e 100644
--- a/source/blender/compositor/nodes/COM_MaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_MaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cc
index 0edf880400f..0edf880400f 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cc
diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cc
index d082590d21b..d082590d21b 100644
--- a/source/blender/compositor/nodes/COM_MixNode.cpp
+++ b/source/blender/compositor/nodes/COM_MixNode.cc
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cc
index 7cc8f2ea19c..7cc8f2ea19c 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc
diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
index ebace6d5fff..ebace6d5fff 100644
--- a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
diff --git a/source/blender/compositor/nodes/COM_NormalNode.cpp b/source/blender/compositor/nodes/COM_NormalNode.cc
index 1f48a26fd75..1f48a26fd75 100644
--- a/source/blender/compositor/nodes/COM_NormalNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalNode.cc
diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cpp b/source/blender/compositor/nodes/COM_NormalizeNode.cc
index 72459fd477c..72459fd477c 100644
--- a/source/blender/compositor/nodes/COM_NormalizeNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalizeNode.cc
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index dcc1fbdec67..dcc1fbdec67 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cpp b/source/blender/compositor/nodes/COM_PixelateNode.cc
index f238f68727e..f238f68727e 100644
--- a/source/blender/compositor/nodes/COM_PixelateNode.cpp
+++ b/source/blender/compositor/nodes/COM_PixelateNode.cc
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
index 6b9b51631ec..6b9b51631ec 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
index 6be86c04c4d..6be86c04c4d 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
diff --git a/source/blender/compositor/nodes/COM_RotateNode.cpp b/source/blender/compositor/nodes/COM_RotateNode.cc
index cbade778bcb..cbade778bcb 100644
--- a/source/blender/compositor/nodes/COM_RotateNode.cpp
+++ b/source/blender/compositor/nodes/COM_RotateNode.cc
diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cc
index 9ffcd5306b0..9ffcd5306b0 100644
--- a/source/blender/compositor/nodes/COM_ScaleNode.cpp
+++ b/source/blender/compositor/nodes/COM_ScaleNode.cc
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
index 203aa25c9e9..203aa25c9e9 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp b/source/blender/compositor/nodes/COM_SetAlphaNode.cc
index 233a5e96ff4..233a5e96ff4 100644
--- a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cc
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cc
index a84dbf680fe..a84dbf680fe 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cc
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
index 75703876d9e..75703876d9e 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
index 38db080a154..38db080a154 100644
--- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
+++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cc
index d899a54c03c..d899a54c03c 100644
--- a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cc
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cc
index 947774e98ae..947774e98ae 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchNode.cc
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cc
index e4a946e2e9d..e534ebfac9a 100644
--- a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cc
@@ -33,7 +33,7 @@ void SwitchViewNode::convertToOperations(NodeConverter &converter,
/* get the internal index of the socket with a matching name */
int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name));
- nr = max(nr, 0);
+ nr = MAX2(nr, 0);
result = converter.addInputProxy(getInputSocket(nr), false);
converter.mapOutputSocket(getOutputSocket(0), result);
diff --git a/source/blender/compositor/nodes/COM_TextureNode.cpp b/source/blender/compositor/nodes/COM_TextureNode.cc
index 3381b5098d7..3381b5098d7 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.cpp
+++ b/source/blender/compositor/nodes/COM_TextureNode.cc
diff --git a/source/blender/compositor/nodes/COM_TimeNode.cpp b/source/blender/compositor/nodes/COM_TimeNode.cc
index 247e0d11df6..247e0d11df6 100644
--- a/source/blender/compositor/nodes/COM_TimeNode.cpp
+++ b/source/blender/compositor/nodes/COM_TimeNode.cc
diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cpp b/source/blender/compositor/nodes/COM_TonemapNode.cc
index db329e56f9b..db329e56f9b 100644
--- a/source/blender/compositor/nodes/COM_TonemapNode.cpp
+++ b/source/blender/compositor/nodes/COM_TonemapNode.cc
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp b/source/blender/compositor/nodes/COM_TrackPositionNode.cc
index 52e7f7d832b..52e7f7d832b 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cc
diff --git a/source/blender/compositor/nodes/COM_TransformNode.cpp b/source/blender/compositor/nodes/COM_TransformNode.cc
index cd5ba8ba201..cd5ba8ba201 100644
--- a/source/blender/compositor/nodes/COM_TransformNode.cpp
+++ b/source/blender/compositor/nodes/COM_TransformNode.cc
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cpp b/source/blender/compositor/nodes/COM_TranslateNode.cc
index 0e9bf825787..0e9bf825787 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.cpp
+++ b/source/blender/compositor/nodes/COM_TranslateNode.cc
diff --git a/source/blender/compositor/nodes/COM_ValueNode.cpp b/source/blender/compositor/nodes/COM_ValueNode.cc
index 4227db0d10e..4227db0d10e 100644
--- a/source/blender/compositor/nodes/COM_ValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_ValueNode.cc
diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp b/source/blender/compositor/nodes/COM_VectorBlurNode.cc
index a92991c8b49..a92991c8b49 100644
--- a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_VectorBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp b/source/blender/compositor/nodes/COM_VectorCurveNode.cc
index 1201a9f9613..1201a9f9613 100644
--- a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cc
diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
index 7b86fb1d64d..7b86fb1d64d 100644
--- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cc
index fa6c1bc3c28..fa6c1bc3c28 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cc
diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cpp b/source/blender/compositor/nodes/COM_ZCombineNode.cc
index b61c018d029..b61c018d029 100644
--- a/source/blender/compositor/nodes/COM_ZCombineNode.cpp
+++ b/source/blender/compositor/nodes/COM_ZCombineNode.cc
diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
index 668d07c7c3d..668d07c7c3d 100644
--- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp
+++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
index b8465ab7ccf..b8465ab7ccf 100644
--- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp
+++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
index 4510c027d46..4510c027d46 100644
--- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp
+++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
index 684485c40cb..684485c40cb 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
index 35b0092fa5f..35b0092fa5f 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
index 612a71037f7..612a71037f7 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
index f7b7816e1a1..a8ad2a11790 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
@@ -62,7 +62,7 @@ void BokehBlurOperation::initExecution()
int width = this->m_inputBokehProgram->getWidth();
int height = this->m_inputBokehProgram->getHeight();
- float dimension = min(width, height);
+ float dimension = MIN2(width, height);
this->m_bokehMidX = width / 2.0f;
this->m_bokehMidY = height / 2.0f;
@@ -84,7 +84,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
int bufferwidth = inputBuffer->getWidth();
int bufferstartx = inputBuffer->getRect()->xmin;
int bufferstarty = inputBuffer->getRect()->ymin;
- const float max_dim = max(this->getWidth(), this->getHeight());
+ const float max_dim = MAX2(this->getWidth(), this->getHeight());
int pixelSize = this->m_size * max_dim / 100.0f;
zero_v4(color_accum);
@@ -99,10 +99,10 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
int maxy = y + pixelSize;
int minx = x - pixelSize;
int maxx = x + pixelSize;
- miny = max(miny, inputBuffer->getRect()->ymin);
- minx = max(minx, inputBuffer->getRect()->xmin);
- maxy = min(maxy, inputBuffer->getRect()->ymax);
- maxx = min(maxx, inputBuffer->getRect()->xmax);
+ miny = MAX2(miny, inputBuffer->getRect()->ymin);
+ minx = MAX2(minx, inputBuffer->getRect()->xmin);
+ maxy = MIN2(maxy, inputBuffer->getRect()->ymax);
+ maxx = MIN2(maxx, inputBuffer->getRect()->xmax);
int step = getStep();
int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR;
@@ -144,7 +144,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input,
{
rcti newInput;
rcti bokehInput;
- const float max_dim = max(this->getWidth(), this->getHeight());
+ const float max_dim = MAX2(this->getWidth(), this->getHeight());
if (this->m_sizeavailable) {
newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f);
@@ -193,14 +193,14 @@ void BokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr);
if (!this->m_sizeavailable) {
updateSize();
}
- const float max_dim = max(this->getWidth(), this->getHeight());
+ const float max_dim = MAX2(this->getWidth(), this->getHeight());
cl_int radius = this->m_size * max_dim / 100.0f;
cl_int step = this->getStep();
@@ -235,7 +235,7 @@ void BokehBlurOperation::determineResolution(unsigned int resolution[2],
{
NodeOperation::determineResolution(resolution, preferredResolution);
if (this->m_extend_bounds) {
- const float max_dim = max(resolution[0], resolution[1]);
+ const float max_dim = MAX2(resolution[0], resolution[1]);
resolution[0] += 2 * this->m_size * max_dim / 100.0f;
resolution[1] += 2 * this->m_size * max_dim / 100.0f;
}
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h
index 335574a381d..a2e320dfdad 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h
@@ -67,8 +67,8 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
void setExtendBounds(bool extend_bounds)
{
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cpp b/source/blender/compositor/operations/COM_BokehImageOperation.cc
index 473a43c1776..473a43c1776 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc
diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cc
index 662b08bdee9..bb10f3425e2 100644
--- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc
@@ -64,7 +64,7 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi
switch (this->m_maskType) {
case CMP_NODE_MASKTYPE_ADD:
if (inside) {
- output[0] = max(inputMask[0], inputValue[0]);
+ output[0] = MAX2(inputMask[0], inputValue[0]);
}
else {
output[0] = inputMask[0];
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cpp b/source/blender/compositor/operations/COM_BrightnessOperation.cc
index 3ae1b4aaef4..3ae1b4aaef4 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cpp
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
index 9ccf9d7f1ef..9ccf9d7f1ef 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
index 9a1e48177ed..9a1e48177ed 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
index 6bc9fa53c31..6bc9fa53c31 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
index a2c6fd47771..15375589888 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
@@ -95,7 +95,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4],
this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
/* matte operation */
- alpha = inColor[this->m_ids[0]] - max(inColor[this->m_ids[1]], inColor[this->m_ids[2]]);
+ alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]);
/* flip because 0.0 is transparent, not 1.0 */
alpha = 1.0f - alpha;
@@ -116,5 +116,5 @@ void ChannelMatteOperation::executePixelSampled(float output[4],
*/
/* Don't make something that was more transparent less transparent. */
- output[0] = min(alpha, inColor[3]);
+ output[0] = MIN2(alpha, inColor[3]);
}
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h
index 24a5e03a1bf..9a0b888b5a2 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h
@@ -38,12 +38,12 @@ class ChannelMatteOperation : public NodeOperation {
float m_limit_range;
/** ids to use for the operations (max and simple)
- * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]])
+ * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
* the simple operation is using:
* alpha = in[ids[0]] - in[ids[1]]
* but to use the same formula and operation for both we do:
* ids[2] = ids[1]
- * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]])
+ * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
*/
int m_ids[3];
diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
index 52de0198a00..52de0198a00 100644
--- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
index f9eaaf6f7a0..44eef1e19cd 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
@@ -59,7 +59,7 @@ void ColorBalanceASCCDLOperation::executePixelSampled(float output[4],
this->m_inputColorOperation->readSampled(inputColor, x, y, sampler);
float fac = value[0];
- fac = min(1.0f, fac);
+ fac = MIN2(1.0f, fac);
const float mfac = 1.0f - fac;
output[0] = mfac * inputColor[0] +
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
index df44e87a86a..934b7e51aee 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
@@ -64,7 +64,7 @@ void ColorBalanceLGGOperation::executePixelSampled(float output[4],
this->m_inputColorOperation->readSampled(inputColor, x, y, sampler);
float fac = value[0];
- fac = min(1.0f, fac);
+ fac = MIN2(1.0f, fac);
const float mfac = 1.0f - fac;
output[0] = mfac * inputColor[0] +
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
index 60343c28662..02c109e8acd 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
@@ -66,7 +66,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4],
float r, g, b;
float value = inputMask[0];
- value = min(1.0f, value);
+ value = MIN2(1.0f, value);
const float mvalue = 1.0f - value;
float levelShadows = 0.0;
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
index ed107a88953..ed107a88953 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
index a11039852a1..a11039852a1 100644
--- a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp b/source/blender/compositor/operations/COM_ColorMatteOperation.cc
index 17ada8d89b2..17ada8d89b2 100644
--- a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cc
index 4d62a293b78..4d62a293b78 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp b/source/blender/compositor/operations/COM_ColorSpillOperation.cc
index 050792d8dab..8139d71c637 100644
--- a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc
@@ -90,7 +90,7 @@ void ColorSpillOperation::executePixelSampled(float output[4],
float input[4];
this->m_inputFacReader->readSampled(fac, x, y, sampler);
this->m_inputImageReader->readSampled(input, x, y, sampler);
- float rfac = min(1.0f, fac[0]);
+ float rfac = MIN2(1.0f, fac[0]);
float map;
switch (this->m_spillMethod) {
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cc
index 6a16872cae2..6a16872cae2 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cc
diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
index 44468e04ae9..44468e04ae9 100644
--- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
index fe395ecae9e..abf423cc48a 100644
--- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
@@ -63,13 +63,13 @@ void ConvertDepthToRadiusOperation::initExecution()
(this->getHeight() / (float)this->getWidth()) :
(this->getWidth() / (float)this->getHeight());
this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop;
- const float minsz = min(getWidth(), getHeight());
+ const float minsz = MIN2(getWidth(), getHeight());
this->m_dof_sp = minsz /
((cam_sensor / 2.0f) /
- this->m_cam_lens); // <- == aspect * min(img->x, img->y) / tan(0.5f * fov);
+ this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov);
if (this->m_blurPostOperation) {
- m_blurPostOperation->setSigma(min(m_aperture * 128.0f, this->m_maxRadius));
+ m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius));
}
}
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cc
index cccfd407752..cccfd407752 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cc
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
index 1c2570cd251..a5f2ae404e3 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
@@ -92,8 +92,8 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y,
output[3] = in2[3];
/* Make sure we don't return negative color. */
- output[0] = max(output[0], 0.0f);
- output[1] = max(output[1], 0.0f);
- output[2] = max(output[2], 0.0f);
- output[3] = max(output[3], 0.0f);
+ output[0] = MAX2(output[0], 0.0f);
+ output[1] = MAX2(output[1], 0.0f);
+ output[2] = MAX2(output[2], 0.0f);
+ output[3] = MAX2(output[3], 0.0f);
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
index 7e35f6fb4f6..425e87ffa7e 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
@@ -105,10 +105,10 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi
output[3] = output[3] * value[0] + in2[3] * mval;
/* Make sure we don't return negative color. */
- output[0] = max(output[0], 0.0f);
- output[1] = max(output[1], 0.0f);
- output[2] = max(output[2], 0.0f);
- output[3] = max(output[3], 0.0f);
+ output[0] = MAX2(output[0], 0.0f);
+ output[1] = MAX2(output[1], 0.0f);
+ output[2] = MAX2(output[2], 0.0f);
+ output[3] = MAX2(output[3], 0.0f);
}
bool ConvolutionFilterOperation::determineDependingAreaOfInterest(
diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cc
index 408f588871e..9364557169c 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cpp
+++ b/source/blender/compositor/operations/COM_CropOperation.cc
@@ -54,10 +54,10 @@ void CropBaseOperation::updateArea()
local_settings.y2 = height - 1;
}
- this->m_xmax = max(local_settings.x1, local_settings.x2) + 1;
- this->m_xmin = min(local_settings.x1, local_settings.x2);
- this->m_ymax = max(local_settings.y1, local_settings.y2) + 1;
- this->m_ymin = min(local_settings.y1, local_settings.y2);
+ this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1;
+ this->m_xmin = MIN2(local_settings.x1, local_settings.x2);
+ this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1;
+ this->m_ymin = MIN2(local_settings.y1, local_settings.y2);
}
else {
this->m_xmax = 0;
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
index ccd291697cf..ccd291697cf 100644
--- a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
index b58efcf0cca..b58efcf0cca 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cc
index d08f238c4c1..d08f238c4c1 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc
diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cpp b/source/blender/compositor/operations/COM_DespeckleOperation.cc
index 901445c6875..b299c73eabb 100644
--- a/source/blender/compositor/operations/COM_DespeckleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc
@@ -101,7 +101,7 @@ void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*da
COLOR_ADD(TOT_DIV_ONE)
#if 0
- this->m_inputOperation->read(in2, x2, y2, NULL);
+ this->m_inputOperation->read(in2, x2, y2, nullptr);
madd_v4_v4fl(color_mid, in2, this->m_filter[4]);
#endif
diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
index cca99a42c0c..cca99a42c0c 100644
--- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
index b2dfb558028..fbe9fe8ea27 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
@@ -41,7 +41,7 @@ void DilateErodeThresholdOperation::initExecution()
}
else {
if (this->m_inset * 2 > this->m_distance) {
- this->m_scope = max(this->m_inset * 2 - this->m_distance, this->m_distance);
+ this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance);
}
else {
this->m_scope = this->m_distance;
@@ -71,10 +71,10 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
rcti *rect = inputBuffer->getRect();
- const int minx = max(x - this->m_scope, rect->xmin);
- const int miny = max(y - this->m_scope, rect->ymin);
- const int maxx = min(x + this->m_scope, rect->xmax);
- const int maxy = min(y + this->m_scope, rect->ymax);
+ const int minx = MAX2(x - this->m_scope, rect->xmin);
+ const int miny = MAX2(y - this->m_scope, rect->ymin);
+ const int maxx = MIN2(x + this->m_scope, rect->xmax);
+ const int maxy = MIN2(y + this->m_scope, rect->ymax);
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
@@ -87,7 +87,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
if (buffer[offset] < sw) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
- mindist = min(mindist, dis);
+ mindist = MIN2(mindist, dis);
}
offset++;
}
@@ -102,7 +102,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
if (buffer[offset] > sw) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
- mindist = min(mindist, dis);
+ mindist = MIN2(mindist, dis);
}
offset++;
}
@@ -191,10 +191,10 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
rcti *rect = inputBuffer->getRect();
- const int minx = max(x - this->m_scope, rect->xmin);
- const int miny = max(y - this->m_scope, rect->ymin);
- const int maxx = min(x + this->m_scope, rect->xmax);
- const int maxy = min(y + this->m_scope, rect->ymax);
+ const int minx = MAX2(x - this->m_scope, rect->xmin);
+ const int miny = MAX2(y - this->m_scope, rect->ymin);
+ const int maxx = MIN2(x + this->m_scope, rect->xmax);
+ const int maxy = MIN2(y + this->m_scope, rect->ymax);
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
@@ -207,7 +207,7 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
if (dis <= mindist) {
- value = max(buffer[offset], value);
+ value = MAX2(buffer[offset], value);
}
offset++;
}
@@ -238,8 +238,8 @@ void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr);
@@ -270,10 +270,10 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
rcti *rect = inputBuffer->getRect();
- const int minx = max(x - this->m_scope, rect->xmin);
- const int miny = max(y - this->m_scope, rect->ymin);
- const int maxx = min(x + this->m_scope, rect->xmax);
- const int maxy = min(y + this->m_scope, rect->ymax);
+ const int minx = MAX2(x - this->m_scope, rect->xmin);
+ const int miny = MAX2(y - this->m_scope, rect->ymin);
+ const int maxx = MIN2(x + this->m_scope, rect->xmax);
+ const int maxy = MIN2(y + this->m_scope, rect->ymax);
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
@@ -286,7 +286,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
if (dis <= mindist) {
- value = min(buffer[offset], value);
+ value = MIN2(buffer[offset], value);
}
offset++;
}
@@ -298,8 +298,8 @@ void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr);
@@ -360,10 +360,10 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
int half_window = this->m_iterations;
int window = half_window * 2 + 1;
- int xmin = max(0, rect->xmin - half_window);
- int ymin = max(0, rect->ymin - half_window);
- int xmax = min(width, rect->xmax + half_window);
- int ymax = min(height, rect->ymax + half_window);
+ int xmin = MAX2(0, rect->xmin - half_window);
+ int ymin = MAX2(0, rect->ymin - half_window);
+ int xmax = MIN2(width, rect->xmax + half_window);
+ int ymax = MIN2(height, rect->ymax + half_window);
int bwidth = rect->xmax - rect->xmin;
int bheight = rect->ymax - rect->ymin;
@@ -378,7 +378,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
// single row or column of input values, padded with FLT_MAX's to
// simplify the logic.
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
- float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window),
+ float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window),
"dilate erode buf");
// The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
@@ -396,13 +396,13 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (x = 1; x < window; x++) {
- temp[window - 1 - x] = max(temp[window - x], buf[start - x]);
- temp[window - 1 + x] = max(temp[window + x - 2], buf[start + x]);
+ temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]);
+ temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]);
}
start = half_window + (i - 1) * window + 1;
- for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) {
- rectf[bwidth * (y - ymin) + (start + x)] = max(temp[x], temp[x + window - 1]);
+ for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) {
+ rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]);
}
}
}
@@ -421,13 +421,14 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (y = 1; y < window; y++) {
- temp[window - 1 - y] = max(temp[window - y], buf[start - y]);
- temp[window - 1 + y] = max(temp[window + y - 2], buf[start + y]);
+ temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]);
+ temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]);
}
start = half_window + (i - 1) * window + 1;
- for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) {
- rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = max(temp[y], temp[y + window - 1]);
+ for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) {
+ rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y],
+ temp[y + window - 1]);
}
}
}
@@ -489,10 +490,10 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
int half_window = this->m_iterations;
int window = half_window * 2 + 1;
- int xmin = max(0, rect->xmin - half_window);
- int ymin = max(0, rect->ymin - half_window);
- int xmax = min(width, rect->xmax + half_window);
- int ymax = min(height, rect->ymax + half_window);
+ int xmin = MAX2(0, rect->xmin - half_window);
+ int ymin = MAX2(0, rect->ymin - half_window);
+ int xmax = MIN2(width, rect->xmax + half_window);
+ int ymax = MIN2(height, rect->ymax + half_window);
int bwidth = rect->xmax - rect->xmin;
int bheight = rect->ymax - rect->ymin;
@@ -507,7 +508,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
// single row or column of input values, padded with FLT_MAX's to
// simplify the logic.
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
- float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window),
+ float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window),
"dilate erode buf");
// The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
@@ -525,13 +526,13 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (x = 1; x < window; x++) {
- temp[window - 1 - x] = min(temp[window - x], buf[start - x]);
- temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]);
+ temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]);
+ temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]);
}
start = half_window + (i - 1) * window + 1;
- for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) {
- rectf[bwidth * (y - ymin) + (start + x)] = min(temp[x], temp[x + window - 1]);
+ for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) {
+ rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]);
}
}
}
@@ -550,13 +551,14 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (y = 1; y < window; y++) {
- temp[window - 1 - y] = min(temp[window - y], buf[start - y]);
- temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]);
+ temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]);
+ temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]);
}
start = half_window + (i - 1) * window + 1;
- for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) {
- rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = min(temp[y], temp[y + window - 1]);
+ for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) {
+ rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y],
+ temp[y + window - 1]);
}
}
}
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h
index 2af5c8990ee..35f9be89220 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.h
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h
@@ -115,8 +115,8 @@ class DilateDistanceOperation : public NodeOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
class ErodeDistanceOperation : public DilateDistanceOperation {
public:
@@ -131,8 +131,8 @@ class ErodeDistanceOperation : public DilateDistanceOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
class DilateStepOperation : public NodeOperation {
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
index c0b9c9b6f1d..3f0cd4ef255 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
@@ -100,8 +100,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr);
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
index fdb7b82779e..0c220f0e239 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
@@ -61,6 +61,6 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cc
index fcc8bc4670e..fcc8bc4670e 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
index bbc4d63305b..bbc4d63305b 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
index ecc2fc2e85f..ecc2fc2e85f 100644
--- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
index f333cc1ecd9..f333cc1ecd9 100644
--- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cpp b/source/blender/compositor/operations/COM_DotproductOperation.cc
index 5914be21453..5914be21453 100644
--- a/source/blender/compositor/operations/COM_DotproductOperation.cpp
+++ b/source/blender/compositor/operations/COM_DotproductOperation.cc
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
index b548a684ba5..b548a684ba5 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
index 38541f91fc8..a6985a40625 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
@@ -73,7 +73,7 @@ void EllipseMaskOperation::executePixelSampled(float output[4],
switch (this->m_maskType) {
case CMP_NODE_MASKTYPE_ADD:
if (inside) {
- output[0] = max(inputMask[0], inputValue[0]);
+ output[0] = MAX2(inputMask[0], inputValue[0]);
}
else {
output[0] = inputMask[0];
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
index 157c595afcb..b3c1b6b4413 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
@@ -209,7 +209,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
(void)0
// intermediate buffers
- sz = max(src_width, src_height);
+ sz = MAX2(src_width, src_height);
X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf");
Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf");
W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf");
diff --git a/source/blender/compositor/operations/COM_FlipOperation.cpp b/source/blender/compositor/operations/COM_FlipOperation.cc
index 37eaf4868d3..37eaf4868d3 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.cpp
+++ b/source/blender/compositor/operations/COM_FlipOperation.cc
diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
index d67d67f8e57..d67d67f8e57 100644
--- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp
+++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
diff --git a/source/blender/compositor/operations/COM_GammaOperation.cpp b/source/blender/compositor/operations/COM_GammaOperation.cc
index 6baa52a290c..6baa52a290c 100644
--- a/source/blender/compositor/operations/COM_GammaOperation.cpp
+++ b/source/blender/compositor/operations/COM_GammaOperation.cc
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
index 4d3efec7c85..4d3efec7c85 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
index a722a879b8d..a722a879b8d 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
index d489c64953e..ca3173001cb 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
@@ -256,7 +256,7 @@ void GaussianBlurReferenceOperation::initExecution()
void GaussianBlurReferenceOperation::updateGauss()
{
int i;
- int x = max(m_filtersizex, m_filtersizey);
+ int x = MAX2(m_filtersizex, m_filtersizey);
m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array");
for (i = 0; i < x; i++) {
m_maintabs[i] = make_gausstab(i + 1, i + 1);
@@ -333,7 +333,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
void GaussianBlurReferenceOperation::deinitExecution()
{
int x, i;
- x = max(this->m_filtersizex, this->m_filtersizey);
+ x = MAX2(this->m_filtersizex, this->m_filtersizey);
for (i = 0; i < x; i++) {
MEM_freeN(this->m_maintabs[i]);
}
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
index 90333f7dd79..596d439658c 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
@@ -122,8 +122,8 @@ void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel(
"gaussianXBlurOperationKernel", nullptr);
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
index b2bcd79e716..78ea6aa3cc2 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
@@ -42,8 +42,8 @@ class GaussianXBlurOperation : public BlurBaseOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
/**
* \brief initialize the execution
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
index c5b3cf24239..55c1551ca42 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
@@ -122,8 +122,8 @@ void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel(
"gaussianYBlurOperationKernel", nullptr);
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
index d921780876a..8e7440b6fe4 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
@@ -42,8 +42,8 @@ class GaussianYBlurOperation : public BlurBaseOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
/**
* \brief initialize the execution
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cc
index 7b4d38fba3e..7b4d38fba3e 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
index 362905761bb..362905761bb 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cc
index 760b833d1e1..760b833d1e1 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
index 75c2ae51bde..75c2ae51bde 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
index 4fccb62e3df..4fccb62e3df 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
index 1a1922f828c..cfa4b99cd70 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
@@ -54,9 +54,9 @@ void GlareThresholdOperation::executePixelSampled(float output[4],
output[1] -= threshold;
output[2] -= threshold;
- output[0] = max(output[0], 0.0f);
- output[1] = max(output[1], 0.0f);
- output[2] = max(output[2], 0.0f);
+ output[0] = MAX2(output[0], 0.0f);
+ output[1] = MAX2(output[1], 0.0f);
+ output[2] = MAX2(output[2], 0.0f);
}
else {
zero_v3(output);
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
index df30e75cf27..df30e75cf27 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cpp b/source/blender/compositor/operations/COM_IDMaskOperation.cc
index 8113adb9bbc..8113adb9bbc 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cc
index ae5b7293a8c..ae5b7293a8c 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cc
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cc
index 502b33d7e14..502b33d7e14 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cpp
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cc
diff --git a/source/blender/compositor/operations/COM_InvertOperation.cpp b/source/blender/compositor/operations/COM_InvertOperation.cc
index d9f436a3e28..d9f436a3e28 100644
--- a/source/blender/compositor/operations/COM_InvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_InvertOperation.cc
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
index 72bf86facfb..c9cc8ebc045 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
@@ -50,7 +50,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
float average = 0.0f;
if (this->m_axis == 0) {
- const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size);
+ const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size);
for (int cx = start; cx < end; cx++) {
int bufferIndex = (y * bufferWidth + cx);
average += buffer[bufferIndex];
@@ -58,8 +58,8 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
}
}
else {
- const int start = max(0, y - this->m_size + 1),
- end = min(inputBuffer->getHeight(), y + this->m_size);
+ const int start = MAX2(0, y - this->m_size + 1),
+ end = MIN2(inputBuffer->getHeight(), y + this->m_size);
for (int cy = start; cy < end; cy++) {
int bufferIndex = (cy * bufferWidth + x);
average += buffer[bufferIndex];
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cc
index 592f116c451..592f116c451 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc
diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
index b9bb316462d..f4d0d6c6a00 100644
--- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
@@ -63,8 +63,8 @@ void KeyingDespillOperation::executePixelSampled(float output[4],
const int other_1 = (screen_primary_channel + 1) % 3;
const int other_2 = (screen_primary_channel + 2) % 3;
- const int min_channel = min(other_1, other_2);
- const int max_channel = max(other_1, other_2);
+ const int min_channel = MIN2(other_1, other_2);
+ const int max_channel = MAX2(other_1, other_2);
float average_value, amount;
diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cc
index 9ef4217d300..94e65181207 100644
--- a/source/blender/compositor/operations/COM_KeyingOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingOperation.cc
@@ -30,8 +30,8 @@ static float get_pixel_saturation(const float pixelColor[4],
const int other_1 = (primary_channel + 1) % 3;
const int other_2 = (primary_channel + 2) % 3;
- const int min_channel = min(other_1, other_2);
- const int max_channel = max(other_1, other_2);
+ const int min_channel = MIN2(other_1, other_2);
+ const int max_channel = MAX2(other_1, other_2);
const float val = screen_balance * pixelColor[min_channel] +
(1.0f - screen_balance) * pixelColor[max_channel];
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
index 463a6fe49c0..463a6fe49c0 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
index 096930d0a83..2bd7493625e 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
@@ -54,7 +54,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4],
float alpha;
/* one line thread-friend algorithm:
- * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low))));
+ * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low))));
*/
/* test range */
diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cpp b/source/blender/compositor/operations/COM_MapRangeOperation.cc
index 95b3c27ac2f..95b3c27ac2f 100644
--- a/source/blender/compositor/operations/COM_MapRangeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapRangeOperation.cc
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cc
index 32ab63ae028..32ab63ae028 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cc
diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cpp b/source/blender/compositor/operations/COM_MapValueOperation.cc
index 7f2044b9139..7f2044b9139 100644
--- a/source/blender/compositor/operations/COM_MapValueOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapValueOperation.cc
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cc
index ab908590c55..ab908590c55 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cc
diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h
index eba14d10373..67e6b64315c 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.h
+++ b/source/blender/compositor/operations/COM_MaskOperation.h
@@ -84,7 +84,7 @@ class MaskOperation : public NodeOperation {
void setMotionBlurSamples(int samples)
{
- this->m_rasterMaskHandleTot = min(max(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX);
+ this->m_rasterMaskHandleTot = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX);
}
void setMotionBlurShutter(float shutter)
{
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cc
index dbec6dd1874..692c1e70462 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc
@@ -351,7 +351,7 @@ void MathMinimumOperation::executePixelSampled(float output[4],
this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- output[0] = min(inputValue1[0], inputValue2[0]);
+ output[0] = MIN2(inputValue1[0], inputValue2[0]);
clampIfNeeded(output);
}
@@ -367,7 +367,7 @@ void MathMaximumOperation::executePixelSampled(float output[4],
this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- output[0] = max(inputValue1[0], inputValue2[0]);
+ output[0] = MAX2(inputValue1[0], inputValue2[0]);
clampIfNeeded(output);
}
diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cc
index 76a66727a75..11df0900345 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cpp
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -523,9 +523,9 @@ void MixGlareOperation::executePixelSampled(float output[4],
inputColor1[2] = 0.0f;
}
- output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f);
- output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f);
- output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f);
+ output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f);
+ output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f);
+ output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f);
output[3] = inputColor1[3];
clampIfNeeded(output);
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
index 725aacc7d34..725aacc7d34 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cc
index 4f819bf27af..4f819bf27af 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
index 5031d590720..5031d590720 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
index 60936ee1939..60936ee1939 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
index f5176b0a4db..bfc59cabdbf 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
@@ -28,7 +28,7 @@ class MultilayerBaseOperation : public BaseImageOperation {
protected:
RenderLayer *m_renderLayer;
RenderPass *m_renderPass;
- ImBuf *getImBuf();
+ ImBuf *getImBuf() override;
public:
/**
@@ -44,7 +44,7 @@ class MultilayerColorOperation : public MultilayerBaseOperation {
{
this->addOutputSocket(COM_DT_COLOR);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
std::unique_ptr<MetaData> getMetaData() const override;
};
@@ -55,7 +55,7 @@ class MultilayerValueOperation : public MultilayerBaseOperation {
{
this->addOutputSocket(COM_DT_VALUE);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MultilayerVectorOperation : public MultilayerBaseOperation {
@@ -65,5 +65,5 @@ class MultilayerVectorOperation : public MultilayerBaseOperation {
{
this->addOutputSocket(COM_DT_VECTOR);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
};
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cc
index a8448685332..a8448685332 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index 7044fe402eb..7044fe402eb 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index bb1b312ffec..bb1b312ffec 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cpp b/source/blender/compositor/operations/COM_PixelateOperation.cc
index 0d810c80ab4..0d810c80ab4 100644
--- a/source/blender/compositor/operations/COM_PixelateOperation.cpp
+++ b/source/blender/compositor/operations/COM_PixelateOperation.cc
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
index d4f2ca7bbe8..d4f2ca7bbe8 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
index c395f795a22..c395f795a22 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
index 81a598e937b..81a598e937b 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cc
index 063421f6525..063421f6525 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cpp
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cc
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
index 7d459b76cb9..7d459b76cb9 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cpp b/source/blender/compositor/operations/COM_QualityStepHelper.cc
index 3eb8d528f7a..3eb8d528f7a 100644
--- a/source/blender/compositor/operations/COM_QualityStepHelper.cpp
+++ b/source/blender/compositor/operations/COM_QualityStepHelper.cc
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cc
index 2977e6685d2..2977e6685d2 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index e32a4cdc9bc..73de60f4c34 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
@@ -234,8 +234,8 @@ std::unique_ptr<MetaData> RenderLayersProg::getMetaData() const
view_layer->name,
BLI_strnlen(view_layer->name, sizeof(view_layer->name))) +
"." + m_passName;
- blender::StringRef cryptomatte_layer_name = blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(
- full_layer_name);
+ blender::StringRef cryptomatte_layer_name =
+ blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name);
callback_data.setCryptomatteKeys(cryptomatte_layer_name);
BKE_stamp_info_callback(&callback_data,
diff --git a/source/blender/compositor/operations/COM_RotateOperation.cpp b/source/blender/compositor/operations/COM_RotateOperation.cc
index 7a21e960c13..9a1f54a6e10 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.cpp
+++ b/source/blender/compositor/operations/COM_RotateOperation.cc
@@ -93,10 +93,10 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input,
const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin);
const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax);
const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax);
- const float minx = min(x1, min(x2, min(x3, x4)));
- const float maxx = max(x1, max(x2, max(x3, x4)));
- const float miny = min(y1, min(y2, min(y3, y4)));
- const float maxy = max(y1, max(y2, max(y3, y4)));
+ const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4)));
+ const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4)));
+ const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4)));
+ const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4)));
newInput.xmax = ceil(maxx) + 1;
newInput.xmin = floor(minx) - 1;
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cc
index 9ec4e474ccd..9ec4e474ccd 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cc
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
index 158ffd4a8c0..158ffd4a8c0 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
index 17029cb3049..17029cb3049 100644
--- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
index cd6e82902cc..cd6e82902cc 100644
--- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cpp b/source/blender/compositor/operations/COM_SetColorOperation.cc
index ffbc20fde9c..ffbc20fde9c 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp b/source/blender/compositor/operations/COM_SetSamplerOperation.cc
index 942d717d19c..942d717d19c 100644
--- a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cpp b/source/blender/compositor/operations/COM_SetValueOperation.cc
index d72a2dfe23d..d72a2dfe23d 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cc
index a0341dbc4df..a0341dbc4df 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc
diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cc
index 53f5fea8795..53f5fea8795 100644
--- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp
+++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cc
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cc
index fb6214c7522..fb6214c7522 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cpp
+++ b/source/blender/compositor/operations/COM_SplitOperation.cc
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
index 7cfa4de7a61..28811d479a5 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
@@ -33,7 +33,7 @@ void SunBeamsOperation::initExecution()
/* convert to pixels */
this->m_source_px[0] = this->m_data.source[0] * this->getWidth();
this->m_source_px[1] = this->m_data.source[1] * this->getHeight();
- this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight());
+ this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight());
}
/**
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cc
index e66cd57cb3f..e66cd57cb3f 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cc
index cb0fc747dcb..4c1d285a69f 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cpp
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cc
@@ -51,9 +51,9 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data)
output[2] /= ((db == 0.0f) ? 1.0f : db);
const float igm = avg->igm;
if (igm != 0.0f) {
- output[0] = powf(max(output[0], 0.0f), igm);
- output[1] = powf(max(output[1], 0.0f), igm);
- output[2] = powf(max(output[2], 0.0f), igm);
+ output[0] = powf(MAX2(output[0], 0.0f), igm);
+ output[1] = powf(MAX2(output[1], 0.0f), igm);
+ output[2] = powf(MAX2(output[2], 0.0f), igm);
}
}
void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data)
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
index ddabfb7cf6c..ddabfb7cf6c 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cc
index 286004cd49b..286004cd49b 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cpp
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
index 414b5bd980a..b96c713a83a 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
@@ -42,7 +42,7 @@ VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation()
this->m_threshold = 1.0f;
this->m_do_size_scale = false;
#ifdef COM_DEFOCUS_SEARCH
- this->m_inputSearchProgram = NULL;
+ this->m_inputSearchProgram = nullptr;
#endif
}
@@ -74,7 +74,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect)
this->determineDependingAreaOfInterest(
rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2);
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar);
@@ -102,7 +102,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
float multiplier_accum[4];
float color_accum[4];
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
int maxBlurScalar = tileData->maxBlurScalar;
@@ -114,16 +114,16 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
this->m_inputSearchProgram->read(search,
x / InverseSearchRadiusOperation::DIVIDER,
y / InverseSearchRadiusOperation::DIVIDER,
- NULL);
+ nullptr);
int minx = search[0];
int miny = search[1];
int maxx = search[2];
int maxy = search[3];
#else
- int minx = max(x - maxBlurScalar, 0);
- int miny = max(y - maxBlurScalar, 0);
- int maxx = min(x + maxBlurScalar, (int)m_width);
- int maxy = min(y + maxBlurScalar, (int)m_height);
+ int minx = MAX2(x - maxBlurScalar, 0);
+ int miny = MAX2(y - maxBlurScalar, 0);
+ int maxx = MIN2(x + maxBlurScalar, (int)m_width);
+ int maxy = MIN2(y + maxBlurScalar, (int)m_height);
#endif
{
inputSizeBuffer->readNoCheck(tempSize, x, y);
@@ -145,7 +145,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR;
for (int nx = minx; nx < maxx; nx += addXStepValue) {
if (nx != x || ny != y) {
- float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
+ float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
if (size > this->m_threshold) {
float dx = nx - x;
if (size > fabsf(dx) && size > fabsf(dy)) {
@@ -185,8 +185,8 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr);
@@ -197,7 +197,7 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer(
inputMemoryBuffers);
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur);
@@ -225,7 +225,7 @@ void VariableSizeBokehBlurOperation::deinitExecution()
this->m_inputBokehProgram = nullptr;
this->m_inputSizeProgram = nullptr;
#ifdef COM_DEFOCUS_SEARCH
- this->m_inputSearchProgram = NULL;
+ this->m_inputSearchProgram = nullptr;
#endif
}
@@ -235,7 +235,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(
rcti newInput;
rcti bokehInput;
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
int maxBlurScalar = this->m_maxBlur * scalar;
@@ -281,7 +281,7 @@ InverseSearchRadiusOperation::InverseSearchRadiusOperation()
this->addInputSocket(COM_DT_VALUE, COM_SC_NO_RESIZE); // radius
this->addOutputSocket(COM_DT_COLOR);
this->setComplex(true);
- this->m_inputRadius = NULL;
+ this->m_inputRadius = nullptr;
}
void InverseSearchRadiusOperation::initExecution()
@@ -359,7 +359,7 @@ void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data)
void InverseSearchRadiusOperation::deinitExecution()
{
- this->m_inputRadius = NULL;
+ this->m_inputRadius = nullptr;
}
void InverseSearchRadiusOperation::determineResolution(unsigned int resolution[2],
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
index 258b5d385c0..fe927f791fa 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
@@ -80,8 +80,8 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
#ifdef COM_DEFOCUS_SEARCH
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index d6894dfc8ad..f03d702dc58 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
@@ -847,7 +847,7 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd,
* overestimates the contribution of foreground pixels but looks a
* bit better without a sudden cutoff. */
blendfac = ((samples - step) / (float)samples);
- /* smoothstep to make it look a bit nicer as well */
+ /* Smooth-step to make it look a bit nicer as well. */
blendfac = 3.0f * pow(blendfac, 2.0f) - 2.0f * pow(blendfac, 3.0f);
/* accum */
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
index a883237f870..a883237f870 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 025dde8e866..025dde8e866 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cc
diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cc
index 37b7d68d495..37b7d68d495 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.cpp
+++ b/source/blender/compositor/operations/COM_WrapOperation.cc
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cc
index 9fb995bf463..8d38dbfe180 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc
@@ -143,9 +143,9 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device,
}
// STEP 2
- list<cl_mem> *clMemToCleanUp = new list<cl_mem>();
+ std::list<cl_mem> *clMemToCleanUp = new std::list<cl_mem>();
clMemToCleanUp->push_back(clOutputBuffer);
- list<cl_kernel> *clKernelsToCleanUp = new list<cl_kernel>();
+ std::list<cl_kernel> *clKernelsToCleanUp = new std::list<cl_kernel>();
this->m_input->executeOpenCL(device,
outputBuffer,
diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cc
index 22a37a4583e..26d3f2c7dc4 100644
--- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp
+++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc
@@ -83,7 +83,7 @@ void ZCombineAlphaOperation::executePixelSampled(float output[4],
output[0] = fac * color1[0] + ifac * color2[0];
output[1] = fac * color1[1] + ifac * color2[1];
output[2] = fac * color1[2] + ifac * color2[2];
- output[3] = max(color1[3], color2[3]);
+ output[3] = MAX2(color1[3], color2[3]);
}
void ZCombineOperation::deinitExecution()
@@ -149,7 +149,7 @@ void ZCombineMaskAlphaOperation::executePixelSampled(float output[4],
output[0] = color1[0] * mfac + color2[0] * fac;
output[1] = color1[1] * mfac + color2[1] * fac;
output[2] = color1[2] * mfac + color2[2] * fac;
- output[3] = max(color1[3], color2[3]);
+ output[3] = MAX2(color1[3], color2[3]);
}
void ZCombineMaskOperation::deinitExecution()
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 96b4da34347..3cc2ec02165 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -2085,7 +2085,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
- mti->updateDepsgraph(md, &ctx);
+ mti->updateDepsgraph(md, &ctx, graph_->mode);
}
if (BKE_object_modifier_gpencil_use_time(object, md)) {
TimeSourceKey time_src_key;
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 14c91834739..df8c8215d2f 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -33,9 +33,7 @@
#include "MEM_guardedalloc.h"
-#include "DNA_ID.h" /* for ID_Type */
-
-#include "BKE_main.h" /* for MAX_LIBARRAY */
+#include "DNA_ID.h" /* for ID_Type and INDEX_ID_MAX */
#include "BLI_threads.h" /* for SpinLock */
@@ -111,10 +109,10 @@ struct Depsgraph {
bool need_update;
/* Indicates which ID types were updated. */
- char id_type_updated[MAX_LIBARRAY];
+ char id_type_updated[INDEX_ID_MAX];
/* Indicates type of IDs present in the depsgraph. */
- char id_type_exist[MAX_LIBARRAY];
+ char id_type_exist[INDEX_ID_MAX];
/* Quick-Access Temp Data ............. */
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index dff9e302fdf..196b46953c4 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -234,6 +234,9 @@ data_to_c_simple(engines/eevee/shaders/effect_dof_resolve_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_scatter_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_scatter_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_setup_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_reflection_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_reflection_resolve_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_reflection_trace_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC)
@@ -242,7 +245,6 @@ data_to_c_simple(engines/eevee/shaders/effect_velocity_tile_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_subsurface_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_translucency_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC)
@@ -263,6 +265,7 @@ data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/random_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
index 5f8e0106337..7986d7a2810 100644
--- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -834,7 +834,7 @@ static void dof_scatter_pass_init(EEVEE_FramebufferList *fbl,
int input_size[2], target_size[2];
GPU_texture_get_mipmap_size(fx->dof_half_res_color_tx, 0, input_size);
GPU_texture_get_mipmap_size(fx->dof_bg_color_tx, 0, target_size);
- /* Draw a sprite for every four halfres pixels. */
+ /* Draw a sprite for every four half-res pixels. */
int sprite_count = (input_size[0] / 2) * (input_size[1] / 2);
float target_texel_size[2] = {1.0f / target_size[0], 1.0f / target_size[1]};
const bool use_bokeh_tx = (fx->dof_bokeh_gather_lut_tx != NULL);
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 18d3e453c5d..f4f7acb8862 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -44,7 +44,7 @@ static struct {
#define SETUP_BUFFER(tex, fb, fb_color) \
{ \
eGPUTextureFormat format = (DRW_state_is_scene_render()) ? GPU_RGBA32F : GPU_RGBA16F; \
- DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER | DRW_TEX_MIPMAP); \
+ DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER); \
GPU_framebuffer_ensure_config(&fb, \
{ \
GPU_ATTACHMENT_TEXTURE(dtxl->depth), \
@@ -117,20 +117,27 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
/**
* MinMax Pyramid
*/
- const bool half_res_hiz = true;
- int size[2], div;
- common_data->hiz_mip_offset = (half_res_hiz) ? 1 : 0;
- div = (half_res_hiz) ? 2 : 1;
- size[0] = max_ii(size_fs[0] / div, 1);
- size[1] = max_ii(size_fs[1] / div, 1);
+ int div = 1 << MAX_SCREEN_BUFFERS_LOD_LEVEL;
+ effects->hiz_size[0] = divide_ceil_u(size_fs[0], div) * div;
+ effects->hiz_size[1] = divide_ceil_u(size_fs[1], div) * div;
if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- /* Intel gpu seems to have problem rendering to only depth format */
- DRW_texture_ensure_2d(&txl->maxzbuffer, size[0], size[1], GPU_R32F, DRW_TEX_MIPMAP);
+ /* Intel gpu seems to have problem rendering to only depth hiz_format */
+ DRW_texture_ensure_2d(&txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_R32F, DRW_TEX_MIPMAP);
+ GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer),
+ });
}
else {
DRW_texture_ensure_2d(
- &txl->maxzbuffer, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP);
+ &txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP);
+ GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer),
+ GPU_ATTACHMENT_NONE,
+ });
}
if (fbl->downsample_fb == NULL) {
@@ -138,13 +145,33 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
}
/**
- * Compute Mipmap texel alignment.
+ * Compute hiZ texel alignment.
+ */
+ common_data->hiz_uv_scale[0] = viewport_size[0] / effects->hiz_size[0];
+ common_data->hiz_uv_scale[1] = viewport_size[1] / effects->hiz_size[1];
+
+ /* Compute pixel size. Size is multiplied by 2 because it is applied in NDC [-1..1] range. */
+ sldata->common_data.ssr_pixelsize[0] = 2.0f / size_fs[0];
+ sldata->common_data.ssr_pixelsize[1] = 2.0f / size_fs[1];
+
+ /**
+ * Color buffer with correct down-sampling alignment.
+ * Used for SSReflections & SSRefractions.
*/
- for (int i = 0; i < 10; i++) {
- int mip_size[3];
- GPU_texture_get_mipmap_size(txl->color, i, mip_size);
- common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, i));
- common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, i));
+ if ((effects->enabled_effects & EFFECT_RADIANCE_BUFFER) != 0) {
+ DRW_texture_ensure_2d(&txl->filtered_radiance,
+ UNPACK2(effects->hiz_size),
+ GPU_R11F_G11F_B10F,
+ DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+
+ GPU_framebuffer_ensure_config(&fbl->radiance_filtered_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->filtered_radiance),
+ });
+ }
+ else {
+ txl->filtered_radiance = NULL;
}
/**
@@ -210,7 +237,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
- DRWState downsample_write = DRW_STATE_WRITE_DEPTH;
+ DRWState downsample_write = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS;
DRWShadingGroup *grp;
/* Intel gpu seems to have problem rendering to only depth format.
@@ -221,12 +248,17 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- {
+ if (effects->enabled_effects & EFFECT_RADIANCE_BUFFER) {
+ DRW_PASS_CREATE(psl->color_copy_ps, DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(EEVEE_shaders_effect_color_copy_sh_get(), psl->color_copy_ps);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "source", &e_data.color_src, GPU_SAMPLER_DEFAULT);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
DRW_PASS_CREATE(psl->color_downsample_ps, DRW_STATE_WRITE_COLOR);
grp = DRW_shgroup_create(EEVEE_shaders_effect_downsample_sh_get(), psl->color_downsample_ps);
- DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src);
- DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_uniform_texture_ex(grp, "source", txl->filtered_radiance, GPU_SAMPLER_FILTER);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
@@ -241,34 +273,21 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
/* Perform min/max down-sample. */
- DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write);
grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downlevel_sh_get(), psl->maxz_downlevel_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &txl->maxzbuffer);
- DRW_shgroup_call(grp, quad, NULL);
-
- /* Copy depth buffer to halfres top level of HiZ */
-
- DRW_PASS_CREATE(psl->maxz_downdepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
- grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_sh_get(), psl->maxz_downdepth_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
- DRW_shgroup_call(grp, quad, NULL);
-
- DRW_PASS_CREATE(psl->maxz_downdepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
- grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(),
- psl->maxz_downdepth_layer_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
- DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &txl->maxzbuffer, GPU_SAMPLER_DEFAULT);
DRW_shgroup_call(grp, quad, NULL);
- DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ /* Copy depth buffer to top level of HiZ */
+ DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write);
grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_sh_get(), psl->maxz_copydepth_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT);
DRW_shgroup_call(grp, quad, NULL);
- DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write);
grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(),
psl->maxz_copydepth_layer_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT);
DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
DRW_shgroup_call(grp, quad, NULL);
}
@@ -331,12 +350,6 @@ static void max_downsample_cb(void *vedata, int UNUSED(level))
DRW_draw_pass(psl->maxz_downlevel_ps);
}
-static void simple_downsample_cb(void *vedata, int UNUSED(level))
-{
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- DRW_draw_pass(psl->color_downsample_ps);
-}
-
static void simple_downsample_cube_cb(void *vedata, int level)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
@@ -348,58 +361,22 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_TextureList *txl = vedata->txl;
e_data.depth_src = depth_src;
e_data.depth_src_layer = layer;
-#if 0 /* Not required for now */
- DRW_stats_group_start("Min buffer");
- /* Copy depth buffer to min texture top level */
- GPU_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0);
- GPU_framebuffer_bind(fbl->downsample_fb);
- if (layer >= 0) {
- DRW_draw_pass(psl->minz_downdepth_layer_ps);
- }
- else {
- DRW_draw_pass(psl->minz_downdepth_ps);
- }
- GPU_framebuffer_texture_detach(stl->g_data->minzbuffer);
-
- /* Create lower levels */
- GPU_framebuffer_recursive_downsample(
- fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata);
- DRW_stats_group_end();
-#endif
- int minmax_size[3], depth_size[3];
- GPU_texture_get_mipmap_size(depth_src, 0, depth_size);
- GPU_texture_get_mipmap_size(txl->maxzbuffer, 0, minmax_size);
- bool is_full_res_minmaxz = equals_v2v2_int(minmax_size, depth_size);
-
DRW_stats_group_start("Max buffer");
/* Copy depth buffer to max texture top level */
- GPU_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0);
- GPU_framebuffer_bind(fbl->downsample_fb);
+ GPU_framebuffer_bind(fbl->maxzbuffer_fb);
if (layer >= 0) {
- if (is_full_res_minmaxz) {
- DRW_draw_pass(psl->maxz_copydepth_layer_ps);
- }
- else {
- DRW_draw_pass(psl->maxz_downdepth_layer_ps);
- }
+ DRW_draw_pass(psl->maxz_copydepth_layer_ps);
}
else {
- if (is_full_res_minmaxz) {
- DRW_draw_pass(psl->maxz_copydepth_ps);
- }
- else {
- DRW_draw_pass(psl->maxz_downdepth_ps);
- }
+ DRW_draw_pass(psl->maxz_copydepth_ps);
}
-
/* Create lower levels */
- GPU_framebuffer_recursive_downsample(fbl->downsample_fb, 8, &max_downsample_cb, vedata);
- GPU_framebuffer_texture_detach(fbl->downsample_fb, txl->maxzbuffer);
+ GPU_framebuffer_recursive_downsample(
+ fbl->maxzbuffer_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &max_downsample_cb, vedata);
DRW_stats_group_end();
/* Restore */
@@ -412,19 +389,28 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l
}
}
+static void downsample_radiance_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->color_downsample_ps);
+}
+
/**
* Simple down-sampling algorithm. Reconstruct mip chain up to mip level.
*/
-void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
+void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *texture_src)
{
+ EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
+
e_data.color_src = texture_src;
+ DRW_stats_group_start("Downsample Radiance");
- /* Create lower levels */
- DRW_stats_group_start("Downsample buffer");
- GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0);
- GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cb, vedata);
- GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src);
+ GPU_framebuffer_bind(fbl->radiance_filtered_fb);
+ DRW_draw_pass(psl->color_copy_ps);
+
+ GPU_framebuffer_recursive_downsample(
+ fbl->radiance_filtered_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_radiance_cb, vedata);
DRW_stats_group_end();
}
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 582bfad323b..ae726d7af9a 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -69,7 +69,7 @@ static void eevee_engine_init(void *ved)
stl->g_data->render_timesteps = 1;
/* Main Buffer */
- DRW_texture_ensure_fullscreen_2d(&txl->color, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+ DRW_texture_ensure_fullscreen_2d(&txl->color, GPU_RGBA16F, DRW_TEX_FILTER);
GPU_framebuffer_ensure_config(&fbl->main_fb,
{GPU_ATTACHMENT_TEXTURE(dtxl->depth),
@@ -286,7 +286,7 @@ static void eevee_draw_scene(void *vedata)
EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
DRW_stats_group_end();
- EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+ EEVEE_occlusion_compute(sldata, vedata);
EEVEE_volumes_compute(sldata, vedata);
/* Shading pass */
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 7688039d0a8..e2e865bcfad 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -50,12 +50,10 @@
#include "WM_types.h"
static struct {
- struct GPUTexture *hammersley;
struct GPUTexture *planar_pool_placeholder;
struct GPUTexture *depth_placeholder;
struct GPUTexture *depth_array_placeholder;
- struct GPUVertFormat *format_probe_display_cube;
struct GPUVertFormat *format_probe_display_planar;
} e_data = {NULL}; /* Engine data */
@@ -90,41 +88,23 @@ bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data)
return vis_in && oed->ob_vis;
}
-static struct GPUTexture *create_hammersley_sample_texture(int samples)
-{
- struct GPUTexture *tex;
- float(*texels)[2] = MEM_mallocN(sizeof(float[2]) * samples, "hammersley_tex");
- int i;
-
- for (i = 0; i < samples; i++) {
- double dphi;
- BLI_hammersley_1d(i, &dphi);
- float phi = (float)dphi * 2.0f * M_PI;
- texels[i][0] = cosf(phi);
- texels[i][1] = sinf(phi);
- }
-
- tex = DRW_texture_create_1d(samples, GPU_RG16F, DRW_TEX_WRAP, (float *)texels);
- MEM_freeN(texels);
- return tex;
-}
-
static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
{
EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *fx = stl->effects;
/* XXX TODO OPTIMIZATION: This is a complete waist of texture memory.
* Instead of allocating each planar probe for each viewport,
* only alloc them once using the biggest viewport resolution. */
- const float *viewport_size = DRW_viewport_size_get();
/* TODO get screen percentage from layer setting */
// const DRWContextState *draw_ctx = DRW_context_state_get();
// ViewLayer *view_layer = draw_ctx->view_layer;
- float screen_percentage = 1.0f;
+ int screen_divider = 1;
- int width = max_ii(1, (int)(viewport_size[0] * screen_percentage));
- int height = max_ii(1, (int)(viewport_size[1] * screen_percentage));
+ int width = max_ii(1, fx->hiz_size[0] / screen_divider);
+ int height = max_ii(1, fx->hiz_size[1] / screen_divider);
/* Fix case were the pool was allocated width the dummy size (1,1,1). */
if (txl->planar_pool && (num_planar_ref > 0) &&
@@ -139,12 +119,12 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
if (num_planar_ref > 0) {
txl->planar_pool = DRW_texture_create_2d_array(width,
height,
- max_ii(1, num_planar_ref),
+ num_planar_ref,
GPU_R11F_G11F_B10F,
DRW_TEX_FILTER | DRW_TEX_MIPMAP,
NULL);
txl->planar_depth = DRW_texture_create_2d_array(
- width, height, max_ii(1, num_planar_ref), GPU_DEPTH_COMPONENT24, 0, NULL);
+ width, height, num_planar_ref, GPU_DEPTH_COMPONENT24, 0, NULL);
}
else if (num_planar_ref == 0) {
/* Makes Opengl Happy : Create a placeholder texture that will never be sampled but still
@@ -165,10 +145,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
vedata->info[0] = '\0';
- if (!e_data.hammersley) {
- EEVEE_shaders_lightprobe_shaders_init();
- e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE);
- }
+ EEVEE_shaders_material_shaders_init();
memset(stl->g_data->bake_views, 0, sizeof(stl->g_data->bake_views));
memset(stl->g_data->cube_views, 0, sizeof(stl->g_data->cube_views));
@@ -243,15 +220,13 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1);
- DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1);
+ DRW_shgroup_uniform_float(grp, "roughness", &pinfo->roughness, 1);
DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1);
DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1);
DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1);
DRW_shgroup_uniform_float(grp, "fireflyFactor", &pinfo->firefly_fac, 1);
DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1);
- DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
// DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
@@ -269,10 +244,8 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1);
#else
DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1);
DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1);
DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
- DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
#endif
DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
@@ -291,11 +264,9 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1);
DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1);
DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1);
DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1);
DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1);
DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1);
- DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
@@ -674,10 +645,12 @@ static void lightbake_planar_ensure_view(EEVEE_PlanarReflection *eplanar,
const DRWView *main_view,
DRWView **r_planar_view)
{
- float winmat[4][4], viewmat[4][4];
+ float winmat[4][4], viewmat[4][4], persmat[4][4];
DRW_view_viewmat_get(main_view, viewmat, false);
/* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */
DRW_view_winmat_get(main_view, winmat, false);
+ DRW_view_persmat_get(main_view, persmat, false);
+
/* Invert X to avoid flipping the triangle facing direction. */
winmat[0][0] = -winmat[0][0];
winmat[1][0] = -winmat[1][0];
@@ -729,7 +702,6 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
/* For shading, save max level of the octahedron map */
sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len;
- sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL;
sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res;
sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing);
sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len);
@@ -959,7 +931,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
DRW_draw_pass(psl->probe_background);
EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
- EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer);
+ EEVEE_occlusion_compute(sldata, vedata);
GPU_framebuffer_bind(fbl->planarref_fb);
@@ -1043,8 +1015,8 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
/* Disney Roughness */
pinfo->roughness = square_f(pinfo->roughness);
/* Distribute Roughness across lod more evenly */
- pinfo->roughness = square_f(square_f(pinfo->roughness));
- CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */
+ pinfo->roughness = square_f(pinfo->roughness);
+ CLAMP(pinfo->roughness, 1e-4f, 0.9999f); /* Avoid artifacts */
#if 1 /* Variable Sample count and bias (fast) */
switch (i) {
@@ -1076,10 +1048,7 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
CLAMP(filter_quality, 1.0f, 8.0f);
pinfo->samples_len *= filter_quality;
- pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- pinfo->lodfactor = bias +
- 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) /
- log(2);
+ pinfo->lodfactor = bias + 0.5f * log(square_f(target_size) / pinfo->samples_len) / log(2);
pinfo->firefly_fac = (firefly_fac > 0.0) ? firefly_fac : 1e16;
GPU_framebuffer_ensure_config(&fb,
@@ -1127,10 +1096,7 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
#ifndef IRRADIANCE_SH_L2
/* Tweaking parameters to balance perf. vs precision */
const float bias = 0.0f;
- pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- pinfo->lodfactor = bias + 0.5f *
- log((float)(target_size * target_size) * pinfo->samples_len_inv) /
- log(2);
+ pinfo->lodfactor = bias + 0.5f * log(square_f(target_size) / pinfo->samples_len) / log(2);
pinfo->lod_rt_max = log2_floor_u(target_size) - 2.0f;
#else
pinfo->shres = 32; /* Less texture fetches & reduce branches */
@@ -1168,7 +1134,6 @@ void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
LightCache *light_cache = vedata->stl->g_data->light_cache;
pinfo->samples_len = 512.0f; /* TODO refine */
- pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
pinfo->shres = vis_size;
pinfo->visibility_range = vis_range;
pinfo->visibility_blur = vis_blur;
@@ -1220,7 +1185,7 @@ static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata)
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->planar_pool)});
GPU_framebuffer_recursive_downsample(
- fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata);
+ fbl->planar_downsample_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_planar, vedata);
DRW_stats_group_end();
}
@@ -1291,9 +1256,7 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
void EEVEE_lightprobes_free(void)
{
- MEM_SAFE_FREE(e_data.format_probe_display_cube);
MEM_SAFE_FREE(e_data.format_probe_display_planar);
- DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
DRW_TEXTURE_FREE_SAFE(e_data.planar_pool_placeholder);
DRW_TEXTURE_FREE_SAFE(e_data.depth_placeholder);
DRW_TEXTURE_FREE_SAFE(e_data.depth_array_placeholder);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 9d74d916265..042fa621117 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -128,7 +128,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_float_copy(
shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0);
if (use_ssrefraction) {
- DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color);
+ DRW_shgroup_uniform_texture_ref(
+ shgrp, "refractColorBuffer", &vedata->txl->filtered_radiance);
}
}
if (use_alpha_blend) {
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index a3b581357e0..8f8317498ec 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -62,7 +62,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->ao_dist = scene_eval->eevee.gtao_distance;
common_data->ao_factor = scene_eval->eevee.gtao_factor;
- common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality;
+ common_data->ao_quality = scene_eval->eevee.gtao_quality;
if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
common_data->ao_settings = 1.0f; /* USE_AO */
@@ -157,8 +157,6 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_EffectsInfo *effects = stl->effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
-
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
/** Occlusion algorithm overview
*
@@ -176,21 +174,9 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
psl->ao_horizon_search);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- DRW_shgroup_call(grp, quad, NULL);
-
- DRW_PASS_CREATE(psl->ao_horizon_search_layer, DRW_STATE_WRITE_COLOR);
- grp = DRW_shgroup_create(EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(),
- psl->ao_horizon_search_layer);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
- DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
- DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
if (G.debug_value == 6) {
DRW_PASS_CREATE(psl->ao_horizon_debug, DRW_STATE_WRITE_COLOR);
@@ -203,15 +189,12 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons_renderpass);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
}
-void EEVEE_occlusion_compute(EEVEE_ViewLayerData *UNUSED(sldata),
- EEVEE_Data *vedata,
- struct GPUTexture *depth_src,
- int layer)
+void EEVEE_occlusion_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
@@ -220,17 +203,10 @@ void EEVEE_occlusion_compute(EEVEE_ViewLayerData *UNUSED(sldata),
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
DRW_stats_group_start("GTAO Horizon Scan");
- effects->ao_src_depth = depth_src;
- effects->ao_depth_layer = layer;
GPU_framebuffer_bind(fbl->gtao_fb);
- if (layer >= 0) {
- DRW_draw_pass(psl->ao_horizon_search_layer);
- }
- else {
- DRW_draw_pass(psl->ao_horizon_search);
- }
+ DRW_draw_pass(psl->ao_horizon_search);
if (GPU_mip_render_workaround() ||
GPU_type_matches(GPU_DEVICE_INTEL_UHD, GPU_OS_WIN, GPU_DRIVER_ANY)) {
@@ -275,7 +251,7 @@ void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *
/* Update the min_max/horizon buffers so the refraction materials appear in it. */
EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
- EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+ EEVEE_occlusion_compute(sldata, vedata);
GPU_framebuffer_bind(fbl->ao_accum_fb);
DRW_draw_pass(psl->ao_accum_ps);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 4e32854dedc..e98ba4136ed 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -63,7 +63,6 @@ extern struct DrawEngineType draw_engine_eevee_type;
/* Only define one of these. */
// #define IRRADIANCE_SH_L2
#define IRRADIANCE_HL2
-#define HAMMERSLEY_SIZE 1024
#if defined(IRRADIANCE_SH_L2)
# define SHADER_IRRADIANCE "#define IRRADIANCE_SH_L2\n"
@@ -161,7 +160,7 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d)
((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0))))
#define MIN_CUBE_LOD_LEVEL 3
-#define MAX_PLANAR_LOD_LEVEL 9
+#define MAX_SCREEN_BUFFERS_LOD_LEVEL 6
/* All the renderpasses that use the GPUMaterial for accumulation */
#define EEVEE_RENDERPASSES_MATERIAL \
@@ -201,13 +200,6 @@ enum {
KEY_SHADOW = (1 << 3),
};
-/* SSR shader variations */
-typedef enum EEVEE_SSRShaderOptions {
- SSR_RESOLVE = (1 << 0),
- SSR_FULL_TRACE = (1 << 1),
- SSR_MAX_SHADER = (1 << 2),
-} EEVEE_SSRShaderOptions;
-
/* DOF Gather pass shader variations */
typedef enum EEVEE_DofGatherPass {
DOF_GATHER_FOREGROUND = 0,
@@ -271,7 +263,6 @@ typedef struct EEVEE_PassList {
/* Effects */
struct DRWPass *ao_horizon_search;
- struct DRWPass *ao_horizon_search_layer;
struct DRWPass *ao_horizon_debug;
struct DRWPass *ao_accum_ps;
struct DRWPass *mist_accum_ps;
@@ -308,6 +299,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *sss_blur_ps;
struct DRWPass *sss_resolve_ps;
struct DRWPass *sss_translucency_ps;
+ struct DRWPass *color_copy_ps;
struct DRWPass *color_downsample_ps;
struct DRWPass *color_downsample_cube_ps;
struct DRWPass *velocity_object;
@@ -320,13 +312,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *alpha_checker;
/* HiZ */
- struct DRWPass *minz_downlevel_ps;
struct DRWPass *maxz_downlevel_ps;
- struct DRWPass *minz_downdepth_ps;
- struct DRWPass *maxz_downdepth_ps;
- struct DRWPass *minz_downdepth_layer_ps;
- struct DRWPass *maxz_downdepth_layer_ps;
- struct DRWPass *minz_copydepth_ps;
struct DRWPass *maxz_copydepth_ps;
struct DRWPass *maxz_copydepth_layer_ps;
@@ -362,6 +348,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *gtao_fb;
struct GPUFrameBuffer *gtao_debug_fb;
struct GPUFrameBuffer *downsample_fb;
+ struct GPUFrameBuffer *maxzbuffer_fb;
struct GPUFrameBuffer *bloom_blit_fb;
struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP];
struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1];
@@ -394,7 +381,6 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *volumetric_integ_fb;
struct GPUFrameBuffer *volumetric_accum_fb;
struct GPUFrameBuffer *screen_tracing_fb;
- struct GPUFrameBuffer *refract_fb;
struct GPUFrameBuffer *mist_accum_fb;
struct GPUFrameBuffer *material_accum_fb;
struct GPUFrameBuffer *renderpass_fb;
@@ -412,6 +398,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *main_color_fb;
struct GPUFrameBuffer *effect_fb;
struct GPUFrameBuffer *effect_color_fb;
+ struct GPUFrameBuffer *radiance_filtered_fb;
struct GPUFrameBuffer *double_buffer_fb;
struct GPUFrameBuffer *double_buffer_color_fb;
struct GPUFrameBuffer *double_buffer_depth_fb;
@@ -436,7 +423,6 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *ssr_accum;
struct GPUTexture *shadow_accum;
struct GPUTexture *cryptomatte;
- struct GPUTexture *refract_color;
struct GPUTexture *taa_history;
/* Could not be pool texture because of mipmapping. */
struct GPUTexture *dof_reduced_color;
@@ -460,6 +446,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *planar_depth;
struct GPUTexture *maxzbuffer;
+ struct GPUTexture *filtered_radiance;
struct GPUTexture *renderpass;
@@ -612,13 +599,12 @@ typedef struct EEVEE_LightProbesInfo {
float texel_size;
float padding_size;
float samples_len;
- float samples_len_inv;
float near_clip;
float far_clip;
float roughness;
float firefly_fac;
float lodfactor;
- float lod_rt_max, lod_cube_max, lod_planar_max;
+ float lod_rt_max, lod_cube_max;
float visibility_range;
float visibility_blur;
float intensity_fac;
@@ -708,8 +694,9 @@ typedef enum EEVEE_EffectsFlag {
EFFECT_REFRACT = (1 << 6),
EFFECT_GTAO = (1 << 7),
EFFECT_TAA = (1 << 8),
- EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */
- EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */
+ EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */
+ EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */
+ EFFECT_RADIANCE_BUFFER = (1 << 10), /* Not really an effect but a feature */
EFFECT_SSS = (1 << 11),
EFFECT_VELOCITY_BUFFER = (1 << 12), /* Not really an effect but a feature */
EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */
@@ -735,12 +722,10 @@ typedef struct EEVEE_EffectsInfo {
bool reflection_trace_full;
bool ssr_was_persp;
bool ssr_was_valid_double_buffer;
- int ssr_neighbor_ofs;
- int ssr_halfres_ofs[2];
struct GPUTexture *ssr_normal_input; /* Textures from pool */
struct GPUTexture *ssr_specrough_input;
struct GPUTexture *ssr_hit_output;
- struct GPUTexture *ssr_pdf_output;
+ struct GPUTexture *ssr_hit_depth;
/* Temporal Anti Aliasing */
int taa_reproject_sample;
int taa_current_sample;
@@ -753,8 +738,6 @@ typedef struct EEVEE_EffectsInfo {
float prev_drw_persmat[4][4]; /* Used for checking view validity and reprojection. */
struct DRWView *taa_view;
/* Ambient Occlusion */
- int ao_depth_layer;
- struct GPUTexture *ao_src_depth; /* pointer copy */
struct GPUTexture *gtao_horizons; /* Textures from pool */
struct GPUTexture *gtao_horizons_renderpass; /* Texture when rendering render pass */
struct GPUTexture *gtao_horizons_debug;
@@ -817,11 +800,10 @@ typedef struct EEVEE_EffectsInfo {
struct GPUTexture *dof_scatter_src_tx;
struct GPUTexture *dof_reduce_input_coc_tx; /* Just references to actual textures. */
struct GPUTexture *dof_reduce_input_color_tx;
- /* Alpha Checker */
- float color_checker_dark[4];
- float color_checker_light[4];
/* Other */
float prev_persmat[4][4];
+ /* Size used by all fullscreen buffers using mipmaps. */
+ int hiz_size[2];
/* Lookdev */
int sphere_size;
eDRWLevelOfDetail sphere_lod;
@@ -858,8 +840,8 @@ typedef struct EEVEE_EffectsInfo {
* - Arrays of vec2/vec3 are padded as arrays of vec4.
* - sizeof(bool) == sizeof(int) in GLSL so use int in C */
typedef struct EEVEE_CommonUniformBuffer {
- float prev_persmat[4][4]; /* mat4 */
- float mip_ratio[10][4]; /* vec2[10] */
+ float prev_persmat[4][4]; /* mat4 */
+ float hiz_uv_scale[2], ssr_uv_scale[2]; /* vec4 */
/* Ambient Occlusion */
/* -- 16 byte aligned -- */
float ao_dist, pad1, ao_factor, pad2; /* vec4 */
@@ -899,15 +881,15 @@ typedef struct EEVEE_CommonUniformBuffer {
int prb_irradiance_vis_size; /* int */
float prb_irradiance_smooth; /* float */
float prb_lod_cube_max; /* float */
- float prb_lod_planar_max; /* float */
/* Misc */
- int hiz_mip_offset; /* int */
int ray_type; /* int */
float ray_depth; /* float */
float alpha_hash_offset; /* float */
float alpha_hash_scale; /* float */
float pad7; /* float */
float pad8; /* float */
+ float pad9; /* float */
+ float pad10; /* float */
} EEVEE_CommonUniformBuffer;
BLI_STATIC_ASSERT_ALIGN(EEVEE_CommonUniformBuffer, 16)
@@ -1184,7 +1166,6 @@ void EEVEE_sample_ellipse(int sample_ofs,
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
-void EEVEE_shaders_lightprobe_shaders_init(void);
void EEVEE_shaders_material_shaders_init(void);
struct DRWShaderLibrary *EEVEE_shader_lib_get(void);
struct GPUShader *EEVEE_shaders_bloom_blit_get(bool high_quality);
@@ -1201,6 +1182,7 @@ struct GPUShader *EEVEE_shaders_depth_of_field_gather_get(EEVEE_DofGatherPass pa
struct GPUShader *EEVEE_shaders_depth_of_field_filter_get(void);
struct GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool is_foreground, bool bokeh_tx);
struct GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_bokeh_tx, bool use_hq_gather);
+struct GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_downsample_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_minz_downlevel_sh_get(void);
@@ -1219,9 +1201,9 @@ struct GPUShader *EEVEE_shaders_effect_motion_blur_hair_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_motion_blur_velocity_tiles_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_motion_blur_velocity_tiles_expand_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_sh_get(void);
-struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(void);
-struct GPUShader *EEVEE_shaders_effect_screen_raytrace_sh_get(EEVEE_SSRShaderOptions options);
+struct GPUShader *EEVEE_shaders_effect_reflection_trace_sh_get(void);
+struct GPUShader *EEVEE_shaders_effect_reflection_resolve_sh_get(void);
struct GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void);
struct GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair);
struct GPUShader *EEVEE_shaders_shadow_sh_get(void);
@@ -1366,10 +1348,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata,
uint tot_samples);
void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- struct GPUTexture *depth_src,
- int layer);
+void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_free(void);
@@ -1472,8 +1451,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
const bool minimal);
void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src);
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
-void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index bc05b7915c3..aaa087f9eb4 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -116,7 +116,7 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
/* TODO 32 bit depth */
DRW_texture_ensure_fullscreen_2d(&dtxl->depth, GPU_DEPTH24_STENCIL8, 0);
- DRW_texture_ensure_fullscreen_2d(&txl->color, GPU_RGBA32F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+ DRW_texture_ensure_fullscreen_2d(&txl->color, GPU_RGBA32F, DRW_TEX_FILTER);
GPU_framebuffer_ensure_config(
&dfbl->default_fb,
@@ -630,7 +630,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
DRW_draw_pass(psl->depth_ps);
/* Create minmax texture */
EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
- EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+ EEVEE_occlusion_compute(sldata, vedata);
EEVEE_volumes_compute(sldata, vedata);
/* Shading pass */
eevee_render_draw_background(vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index 0e16037f42d..5739024993e 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -490,7 +490,7 @@ void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata)
tx = txl->maxzbuffer;
break;
case 2:
- tx = effects->ssr_pdf_output;
+ /* UNUSED */
break;
case 3:
tx = effects->ssr_normal_input;
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index f9e22f5c08d..54f23073bd0 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -32,39 +32,20 @@
#include "GPU_texture.h"
#include "eevee_private.h"
-static struct {
- /* These are just references, not actually allocated */
- struct GPUTexture *depth_src;
-} e_data = {NULL}; /* Engine data */
-
int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
const float *viewport_size = DRW_viewport_size_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- /* Compute pixel size, (shared with contact shadows) */
- copy_v2_v2(common_data->ssr_pixelsize, viewport_size);
- invert_v2(common_data->ssr_pixelsize);
-
if (scene_eval->eevee.flag & SCE_EEVEE_SSR_ENABLED) {
const bool use_refraction = (scene_eval->eevee.flag & SCE_EEVEE_SSR_REFRACTION) != 0;
- if (use_refraction) {
- /* TODO: Opti: Could be shared. */
- DRW_texture_ensure_fullscreen_2d(
- &txl->refract_color, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
-
- GPU_framebuffer_ensure_config(
- &fbl->refract_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->refract_color)});
- }
-
const bool is_persp = DRW_view_is_persp_get(NULL);
if (effects->ssr_was_persp != is_persp) {
effects->ssr_was_persp = is_persp;
@@ -91,6 +72,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->ssr_firefly_fac = FLT_MAX;
}
+ void *owner = (void *)EEVEE_screen_raytrace_init;
const int divisor = (effects->reflection_trace_full) ? 1 : 2;
int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
const int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
@@ -100,25 +82,26 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
tracing_res[0] = max_ii(1, tracing_res[0]);
tracing_res[1] = max_ii(1, tracing_res[1]);
+ common_data->ssr_uv_scale[0] = size_fs[0] / ((float)tracing_res[0] * divisor);
+ common_data->ssr_uv_scale[1] = size_fs[1] / ((float)tracing_res[1] * divisor);
+
/* MRT for the shading pass in order to output needed data for the SSR pass. */
- effects->ssr_specrough_input = DRW_texture_pool_query_2d(
- size_fs[0], size_fs[1], format, &draw_engine_eevee_type);
+ effects->ssr_specrough_input = DRW_texture_pool_query_2d(UNPACK2(size_fs), format, owner);
GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_specrough_input, 2, 0);
/* Ray-tracing output. */
- effects->ssr_hit_output = DRW_texture_pool_query_2d(
- tracing_res[0], tracing_res[1], GPU_RG16I, &draw_engine_eevee_type);
- effects->ssr_pdf_output = DRW_texture_pool_query_2d(
- tracing_res[0], tracing_res[1], GPU_R16F, &draw_engine_eevee_type);
+ effects->ssr_hit_output = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_RGBA16F, owner);
+ effects->ssr_hit_depth = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_R16F, owner);
GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb,
- {GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output),
- GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)});
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output),
+ GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_depth),
+ });
- /* Enable double buffering to be able to read previous frame color */
- return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER |
+ return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER |
((use_refraction) ? EFFECT_REFRACT : 0);
}
@@ -126,7 +109,6 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
GPU_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
effects->ssr_specrough_input = NULL;
effects->ssr_hit_output = NULL;
- effects->ssr_pdf_output = NULL;
return 0;
}
@@ -139,31 +121,28 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
EEVEE_EffectsInfo *effects = stl->effects;
LightCache *lcache = stl->g_data->light_cache;
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
-
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
- EEVEE_SSRShaderOptions options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0;
+ struct GPUShader *trace_shader = EEVEE_shaders_effect_reflection_trace_sh_get();
+ struct GPUShader *resolve_shader = EEVEE_shaders_effect_reflection_resolve_sh_get();
- struct GPUShader *trace_shader = EEVEE_shaders_effect_screen_raytrace_sh_get(options);
- struct GPUShader *resolve_shader = EEVEE_shaders_effect_screen_raytrace_sh_get(SSR_RESOLVE |
- options);
+ int hitbuf_size[3];
+ GPU_texture_get_mipmap_size(effects->ssr_hit_output, 0, hitbuf_size);
/** Screen space raytracing overview
*
* Following Frostbite stochastic SSR.
*
- * - First pass Trace rays across the depth buffer. The hit position and pdf are
+ * - First pass Trace rays across the depth buffer. The hit position and PDF are
* recorded in a RGBA16F render target for each ray (sample).
*
* - We down-sample the previous frame color buffer.
*
* - For each final pixel, we gather neighbors rays and choose a color buffer
- * mipmap for each ray using its pdf. (filtered importance sampling)
+ * mipmap for each ray using its PDF. (filtered importance sampling)
* We then evaluate the lighting from the probes and mix the results together.
*/
DRW_PASS_CREATE(psl->ssr_raytrace, DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
@@ -174,22 +153,23 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- if (!effects->reflection_trace_full) {
- DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1);
- }
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetSize", (float[2]){hitbuf_size[0], hitbuf_size[1]});
+ DRW_shgroup_uniform_float_copy(
+ grp, "randomScale", effects->reflection_trace_full ? 0.0f : 0.5f);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT;
DRW_PASS_CREATE(psl->ssr_resolve, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD);
grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth);
- DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
- DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output);
- DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "hitDepth", &effects->ssr_hit_depth, no_filter);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->filtered_radiance);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
@@ -201,10 +181,9 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
+ DRW_shgroup_uniform_int(grp, "samplePoolOffset", &effects->taa_current_sample, 1);
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
-
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
@@ -216,8 +195,7 @@ void EEVEE_refraction_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
EEVEE_EffectsInfo *effects = stl->effects;
if ((effects->enabled_effects & EFFECT_REFRACT) != 0) {
- GPU_framebuffer_blit(fbl->main_fb, 0, fbl->refract_fb, 0, GPU_COLOR_BIT);
- EEVEE_downsample_buffer(vedata, txl->refract_color, 9);
+ EEVEE_effects_downsample_radiance_buffer(vedata, txl->color);
/* Restore */
GPU_framebuffer_bind(fbl->main_fb);
@@ -233,42 +211,14 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
EEVEE_EffectsInfo *effects = stl->effects;
if (((effects->enabled_effects & EFFECT_SSR) != 0) && stl->g_data->valid_double_buffer) {
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- e_data.depth_src = dtxl->depth;
-
DRW_stats_group_start("SSR");
/* Raytrace. */
GPU_framebuffer_bind(fbl->screen_tracing_fb);
DRW_draw_pass(psl->ssr_raytrace);
- EEVEE_downsample_buffer(vedata, txl->color_double_buffer, 9);
-
- /* Resolve at fullres */
- int samp = (DRW_state_is_image_render()) ? effects->taa_render_sample :
- effects->taa_current_sample;
- /* Doing a neighbor shift only after a few iteration.
- * We wait for a prime number of cycles to avoid noise correlation.
- * This reduces variance faster. */
- effects->ssr_neighbor_ofs = ((samp / 5) % 8) * 4;
- switch ((samp / 11) % 4) {
- case 0:
- effects->ssr_halfres_ofs[0] = 0;
- effects->ssr_halfres_ofs[1] = 0;
- break;
- case 1:
- effects->ssr_halfres_ofs[0] = 0;
- effects->ssr_halfres_ofs[1] = 1;
- break;
- case 2:
- effects->ssr_halfres_ofs[0] = 1;
- effects->ssr_halfres_ofs[1] = 0;
- break;
- case 4:
- effects->ssr_halfres_ofs[0] = 1;
- effects->ssr_halfres_ofs[1] = 1;
- break;
- }
+ EEVEE_effects_downsample_radiance_buffer(vedata, txl->color_double_buffer);
+
GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->ssr_resolve);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index a3e9236dc79..90b7eeb9293 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -41,11 +41,11 @@
#include "eevee_engine.h"
#include "eevee_private.h"
-static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
+static const char *filter_defines =
#if defined(IRRADIANCE_SH_L2)
- "#define IRRADIANCE_SH_L2\n";
+ "#define IRRADIANCE_SH_L2\n";
#elif defined(IRRADIANCE_HL2)
- "#define IRRADIANCE_HL2\n";
+ "#define IRRADIANCE_HL2\n";
#endif
static struct {
@@ -103,7 +103,8 @@ static struct {
struct GPUShader *minz_copydepth_sh;
struct GPUShader *maxz_copydepth_sh;
- /* Simple Down-sample */
+ /* Simple Down-sample. */
+ struct GPUShader *color_copy_sh;
struct GPUShader *downsample_sh;
struct GPUShader *downsample_cube_sh;
@@ -131,7 +132,8 @@ static struct {
struct GPUShader *cryptomatte_sh[2];
/* Screen Space Reflection */
- struct GPUShader *ssr_sh[SSR_MAX_SHADER];
+ struct GPUShader *reflection_trace;
+ struct GPUShader *reflection_resolve;
/* Shadows */
struct GPUShader *shadow_sh;
@@ -216,7 +218,9 @@ extern char datatoc_effect_gtao_frag_glsl[];
extern char datatoc_effect_minmaxz_frag_glsl[];
extern char datatoc_effect_mist_frag_glsl[];
extern char datatoc_effect_motion_blur_frag_glsl[];
-extern char datatoc_effect_ssr_frag_glsl[];
+extern char datatoc_effect_reflection_lib_glsl[];
+extern char datatoc_effect_reflection_resolve_frag_glsl[];
+extern char datatoc_effect_reflection_trace_frag_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
extern char datatoc_effect_temporal_aa_glsl[];
extern char datatoc_effect_translucency_frag_glsl[];
@@ -251,6 +255,7 @@ extern char datatoc_object_motion_vert_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_prepass_frag_glsl[];
extern char datatoc_prepass_vert_glsl[];
+extern char datatoc_random_lib_glsl[];
extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_renderpass_lib_glsl[];
extern char datatoc_renderpass_postprocess_frag_glsl[];
@@ -285,6 +290,7 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_uniforms_lib);
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, random_lib);
DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib);
DRW_SHADER_LIB_ADD(e_data.lib, bsdf_common_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_utiltex_lib);
@@ -301,6 +307,7 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib);
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
DRW_SHADER_LIB_ADD(e_data.lib, effect_dof_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, effect_reflection_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_type_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_diffuse_lib);
@@ -319,35 +326,6 @@ static void eevee_shader_library_ensure(void)
}
}
-void EEVEE_shaders_lightprobe_shaders_init(void)
-{
- BLI_assert(e_data.probe_filter_glossy_sh == NULL);
-
- eevee_shader_library_ensure();
-
- e_data.probe_filter_glossy_sh = DRW_shader_create_with_shaderlib(
- datatoc_lightprobe_vert_glsl,
- datatoc_lightprobe_geom_glsl,
- datatoc_lightprobe_filter_glossy_frag_glsl,
- e_data.lib,
- filter_defines);
-
- e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_lightprobe_filter_diffuse_frag_glsl, e_data.lib, filter_defines);
-
- e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_lightprobe_filter_visibility_frag_glsl, e_data.lib, filter_defines);
-
- e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_lightprobe_grid_fill_frag_glsl, e_data.lib, filter_defines);
-
- e_data.probe_planar_downsample_sh = DRW_shader_create(
- datatoc_lightprobe_planar_downsample_vert_glsl,
- datatoc_lightprobe_planar_downsample_geom_glsl,
- datatoc_lightprobe_planar_downsample_frag_glsl,
- NULL);
-}
-
void EEVEE_shaders_material_shaders_init(void)
{
eevee_shader_library_ensure();
@@ -361,26 +339,54 @@ DRWShaderLibrary *EEVEE_shader_lib_get(void)
GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void)
{
+ if (e_data.probe_filter_glossy_sh == NULL) {
+ e_data.probe_filter_glossy_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_vert_glsl,
+ datatoc_lightprobe_geom_glsl,
+ datatoc_lightprobe_filter_glossy_frag_glsl,
+ e_data.lib,
+ filter_defines);
+ }
return e_data.probe_filter_glossy_sh;
}
GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void)
{
+ if (e_data.probe_filter_diffuse_sh == NULL) {
+ e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_lightprobe_filter_diffuse_frag_glsl, e_data.lib, filter_defines);
+ }
return e_data.probe_filter_diffuse_sh;
}
GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void)
{
+ if (e_data.probe_filter_visibility_sh == NULL) {
+ e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_lightprobe_filter_visibility_frag_glsl, e_data.lib, filter_defines);
+ }
return e_data.probe_filter_visibility_sh;
}
GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void)
{
+ if (e_data.probe_grid_fill_sh == NULL) {
+ e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_lightprobe_grid_fill_frag_glsl, e_data.lib, filter_defines);
+ }
return e_data.probe_grid_fill_sh;
}
GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void)
{
+ if (e_data.probe_planar_downsample_sh == NULL) {
+ e_data.probe_planar_downsample_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_planar_downsample_vert_glsl,
+ datatoc_lightprobe_planar_downsample_geom_glsl,
+ datatoc_lightprobe_planar_downsample_frag_glsl,
+ e_data.lib,
+ NULL);
+ }
return e_data.probe_planar_downsample_sh;
}
@@ -452,10 +458,20 @@ GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void)
/** \name Down-sampling
* \{ */
+GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void)
+{
+ if (e_data.color_copy_sh == NULL) {
+ e_data.color_copy_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_downsample_frag_glsl, e_data.lib, "#define COPY_SRC\n");
+ }
+ return e_data.color_copy_sh;
+}
+
GPUShader *EEVEE_shaders_effect_downsample_sh_get(void)
{
if (e_data.downsample_sh == NULL) {
- e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
+ e_data.downsample_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_downsample_frag_glsl, e_data.lib, NULL);
}
return e_data.downsample_sh;
}
@@ -463,10 +479,12 @@ GPUShader *EEVEE_shaders_effect_downsample_sh_get(void)
GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void)
{
if (e_data.downsample_cube_sh == NULL) {
- e_data.downsample_cube_sh = DRW_shader_create(datatoc_lightprobe_vert_glsl,
- datatoc_lightprobe_geom_glsl,
- datatoc_effect_downsample_cube_frag_glsl,
- NULL);
+ e_data.downsample_cube_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_vert_glsl,
+ datatoc_lightprobe_geom_glsl,
+ datatoc_effect_downsample_cube_frag_glsl,
+ e_data.lib,
+ NULL);
}
return e_data.downsample_cube_sh;
}
@@ -577,7 +595,7 @@ GPUShader *EEVEE_shaders_ggx_refraction_lut_sh_get(void)
{
if (e_data.ggx_refraction_lut_sh == NULL) {
e_data.ggx_refraction_lut_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_btdf_lut_frag_glsl, e_data.lib, "#define HAMMERSLEY_SIZE 8192\n");
+ datatoc_btdf_lut_frag_glsl, e_data.lib, NULL);
}
return e_data.ggx_refraction_lut_sh;
}
@@ -669,20 +687,14 @@ GPUShader *EEVEE_shaders_effect_ambient_occlusion_sh_get(void)
return e_data.gtao_sh;
}
-GPUShader *EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(void)
-{
- if (e_data.gtao_layer_sh == NULL) {
- e_data.gtao_layer_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_effect_gtao_frag_glsl, e_data.lib, "#define LAYERED_DEPTH\n");
- }
- return e_data.gtao_layer_sh;
-}
-
GPUShader *EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(void)
{
if (e_data.gtao_debug_sh == NULL) {
e_data.gtao_debug_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_effect_gtao_frag_glsl, e_data.lib, "#define DEBUG_AO\n");
+ datatoc_effect_gtao_frag_glsl,
+ e_data.lib,
+ "#define DEBUG_AO\n"
+ "#define ENABLE_DEFERED_AO");
}
return e_data.gtao_debug_sh;
}
@@ -733,36 +745,29 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Screen Raytrace
+/** \name Raytraced Reflections
* \{ */
-struct GPUShader *EEVEE_shaders_effect_screen_raytrace_sh_get(EEVEE_SSRShaderOptions options)
+struct GPUShader *EEVEE_shaders_effect_reflection_trace_sh_get(void)
{
- if (e_data.ssr_sh[options] == NULL) {
- DRWShaderLibrary *lib = EEVEE_shader_lib_get();
-
- DynStr *ds_defines = BLI_dynstr_new();
- BLI_dynstr_append(ds_defines, SHADER_DEFINES);
- if (options & SSR_RESOLVE) {
- BLI_dynstr_append(ds_defines, "#define STEP_RESOLVE\n");
- }
- else {
- BLI_dynstr_append(ds_defines, "#define STEP_RAYTRACE\n");
- BLI_dynstr_append(ds_defines, "#define PLANAR_PROBE_RAYTRACE\n");
- }
- if (options & SSR_FULL_TRACE) {
- BLI_dynstr_append(ds_defines, "#define FULLRES\n");
- }
- char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines);
- BLI_dynstr_free(ds_defines);
-
- e_data.ssr_sh[options] = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_effect_ssr_frag_glsl, lib, ssr_define_str);
-
- MEM_freeN(ssr_define_str);
+ if (e_data.reflection_trace == NULL) {
+ e_data.reflection_trace = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_reflection_trace_frag_glsl,
+ e_data.lib,
+ SHADER_DEFINES "#define STEP_RAYTRACE\n");
}
+ return e_data.reflection_trace;
+}
- return e_data.ssr_sh[options];
+struct GPUShader *EEVEE_shaders_effect_reflection_resolve_sh_get(void)
+{
+ if (e_data.reflection_resolve == NULL) {
+ e_data.reflection_resolve = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_reflection_resolve_frag_glsl,
+ e_data.lib,
+ SHADER_DEFINES "#define STEP_RESOLVE\n");
+ }
+ return e_data.reflection_resolve;
}
/** \} */
@@ -961,8 +966,8 @@ GPUShader *EEVEE_shaders_bloom_blit_get(bool high_quality)
const char *define = high_quality ? "#define STEP_BLIT\n"
"#define HIGH_QUALITY\n" :
"#define STEP_BLIT\n";
- e_data.bloom_blit_sh[index] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl,
- define);
+ e_data.bloom_blit_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_bloom_frag_glsl, e_data.lib, define);
}
return e_data.bloom_blit_sh[index];
}
@@ -975,8 +980,8 @@ GPUShader *EEVEE_shaders_bloom_downsample_get(bool high_quality)
const char *define = high_quality ? "#define STEP_DOWNSAMPLE\n"
"#define HIGH_QUALITY\n" :
"#define STEP_DOWNSAMPLE\n";
- e_data.bloom_downsample_sh[index] = DRW_shader_create_fullscreen(
- datatoc_effect_bloom_frag_glsl, define);
+ e_data.bloom_downsample_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_bloom_frag_glsl, e_data.lib, define);
}
return e_data.bloom_downsample_sh[index];
}
@@ -989,8 +994,8 @@ GPUShader *EEVEE_shaders_bloom_upsample_get(bool high_quality)
const char *define = high_quality ? "#define STEP_UPSAMPLE\n"
"#define HIGH_QUALITY\n" :
"#define STEP_UPSAMPLE\n";
- e_data.bloom_upsample_sh[index] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl,
- define);
+ e_data.bloom_upsample_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_bloom_frag_glsl, e_data.lib, define);
}
return e_data.bloom_upsample_sh[index];
}
@@ -1003,8 +1008,8 @@ GPUShader *EEVEE_shaders_bloom_resolve_get(bool high_quality)
const char *define = high_quality ? "#define STEP_RESOLVE\n"
"#define HIGH_QUALITY\n" :
"#define STEP_RESOLVE\n";
- e_data.bloom_resolve_sh[index] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl,
- define);
+ e_data.bloom_resolve_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_bloom_frag_glsl, e_data.lib, define);
}
return e_data.bloom_resolve_sh[index];
}
@@ -1537,6 +1542,7 @@ void EEVEE_shaders_free(void)
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
DRW_SHADER_FREE_SAFE(e_data.lookdev_background);
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
+ DRW_SHADER_FREE_SAFE(e_data.color_copy_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh);
DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh);
@@ -1615,9 +1621,8 @@ void EEVEE_shaders_free(void)
DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[i]);
}
- for (int i = 0; i < SSR_MAX_SHADER; i++) {
- DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
- }
+ DRW_SHADER_FREE_SAFE(e_data.reflection_trace);
+ DRW_SHADER_FREE_SAFE(e_data.reflection_resolve);
DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
if (e_data.default_world) {
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index f6fe9a76c70..51fd1cad41e 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -53,7 +53,7 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
sldata->shadow_ubo = GPU_uniformbuf_create_ex(shadow_ubo_size, NULL, "evShadow");
for (int i = 0; i < 2; i++) {
- sldata->shcasters_buffers[i].bbox = MEM_callocN(
+ sldata->shcasters_buffers[i].bbox = MEM_mallocN(
sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__);
sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__);
sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK;
@@ -133,8 +133,9 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
int id = frontbuffer->count;
/* Make sure shadow_casters is big enough. */
- if (id + 1 >= frontbuffer->alloc_count) {
- frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK;
+ if (id >= frontbuffer->alloc_count) {
+ /* Double capacity to prevent exponential slowdown. */
+ frontbuffer->alloc_count *= 2;
frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
@@ -173,6 +174,7 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
}
EEVEE_BoundBox *aabb = &frontbuffer->bbox[id];
+ /* Note that `*aabb` has not been initialized yet. */
add_v3_v3v3(aabb->center, min, max);
mul_v3_fl(aabb->center, 0.5f);
sub_v3_v3v3(aabb->halfdim, aabb->center, max);
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index ae01aee5dae..7fd39007263 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -208,12 +208,14 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
DRW_shgroup_stencil_mask(shgrp, sss_id);
{
+ eGPUSamplerState state = GPU_SAMPLER_DEFAULT;
+
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_subsurface_first_pass_sh_get(),
psl->sss_blur_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance);
- DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "sssIrradiance", &effects->sss_irradiance, state);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "sssRadius", &effects->sss_radius, state);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
@@ -223,9 +225,9 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
grp = DRW_shgroup_create(EEVEE_shaders_subsurface_second_pass_sh_get(), psl->sss_resolve_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
- DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
- DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "sssIrradiance", &effects->sss_blur, state);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "sssAlbedo", &effects->sss_albedo, state);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "sssRadius", &effects->sss_radius, state);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 473990e1683..dc5c048422b 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -12,7 +12,9 @@
# if !defined(USE_ALPHA_HASH)
# if !defined(DEPTH_SHADER)
# if !defined(USE_ALPHA_BLEND)
-# define ENABLE_DEFERED_AO
+# if !defined(USE_REFRACTION)
+# define ENABLE_DEFERED_AO
+# endif
# endif
# endif
# endif
@@ -31,7 +33,6 @@ uniform sampler2D horizonBuffer;
#define USE_BENT_NORMAL 2
#define USE_DENOISE 4
-#define MAX_LOD 6.0
#define NO_OCCLUSION_DATA OcclusionData(vec4(M_PI, -M_PI, M_PI, -M_PI), 1.0)
struct OcclusionData {
@@ -51,17 +52,13 @@ OcclusionData unpack_occlusion_data(vec4 v)
return OcclusionData((1.0 - v) * vec4(1, -1, 1, -1) * M_PI, 0.0);
}
-/* Returns maximum screen distance an AO ray can travel for a given view depth, in NDC space. */
-vec2 get_ao_area(float view_depth, float radius)
-{
- float homcco = ProjectionMatrix[2][3] * view_depth + ProjectionMatrix[3][3];
- float max_dist = radius / homcco;
- return vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * max_dist;
-}
-
vec2 get_ao_noise(void)
{
- return texelfetch_noise_tex(gl_FragCoord.xy).xy;
+ vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy;
+ /* Decorrelate noise from AA. */
+ /* TODO(fclem) we should use a more general approach for more random number dimentions. */
+ noise = fract(noise * 6.1803402007);
+ return noise;
}
vec2 get_ao_dir(float jitter)
@@ -77,25 +74,37 @@ vec2 get_ao_dir(float jitter)
float search_horizon(vec3 vI,
vec3 vP,
float noise,
- vec2 uv_start,
- vec2 uv_dir,
+ ScreenSpaceRay ssray,
sampler2D depth_tx,
const float inverted,
float radius,
const float sample_count)
{
- float sample_count_inv = 1.0 / sample_count;
/* Init at cos(M_PI). */
float h = (inverted != 0.0) ? 1.0 : -1.0;
- /* TODO(fclem) samples steps should be using the same approach as raytrace. (DDA line algo.) */
- for (float i = 0.0; i < sample_count; i++) {
- float t = ((i + noise) * sample_count_inv);
- vec2 uv = uv_start + uv_dir * t;
- float lod = min(MAX_LOD, max(i - noise, 0.0) * aoQuality);
+ ssray.max_time -= 1.0;
+
+ if (ssray.max_time <= 2.0) {
+ /* Produces self shadowing under this threshold. */
+ return fast_acos(h);
+ }
+
+ float prev_time, time = 0.0;
+ for (float iter = 0.0; time < ssray.max_time && iter < sample_count; iter++) {
+ prev_time = time;
+ /* Gives us good precision at center and ensure we cross at least one pixel per iteration. */
+ time = 1.0 + iter + sqr((iter + noise) / sample_count) * ssray.max_time;
+ float stride = time - prev_time;
+ float lod = (log2(stride) - noise) / (1.0 + aoQuality);
- int mip = int(lod) + hizMipOffset;
- float depth = textureLod(depth_tx, uv * mipRatio[mip].xy, floor(lod)).r;
+ vec2 uv = ssray.origin.xy + ssray.direction.xy * time;
+ float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r;
+
+ if (depth == 1.0 && inverted == 0.0) {
+ /* Skip background. Avoids making shadow on the geometry near the far plane. */
+ continue;
+ }
/* Bias depth a bit to avoid self shadowing issues. */
const float bias = 2.0 * 2.4e-7;
@@ -108,25 +117,16 @@ float search_horizon(vec3 vI,
float s_h = dot(vI, omega_s / len);
/* Blend weight to fade artifacts. */
float dist_ratio = abs(len) / radius;
- /* TODO(fclem) parameter. */
- float dist_fac = sqr(saturate(dist_ratio * 2.0 - 1.0));
+ /* Sphere falloff. */
+ float dist_fac = sqr(saturate(dist_ratio));
+ /* Unbiased, gives too much hard cut behind objects */
+ // float dist_fac = step(0.999, dist_ratio);
- /* Thickness heuristic (Eq. 9). */
if (inverted != 0.0) {
h = min(h, s_h);
}
else {
- /* TODO This need to take the stride distance into account. Now it works because stride is
- * constant. */
- if (s_h < h) {
- /* TODO(fclem) parameter. */
- const float thickness_fac = 0.2;
- s_h = mix(h, s_h, thickness_fac);
- }
- else {
- s_h = max(h, s_h);
- }
- h = mix(s_h, h, dist_fac);
+ h = mix(max(h, s_h), h, dist_fac);
}
}
return fast_acos(h);
@@ -140,7 +140,6 @@ OcclusionData occlusion_search(
}
vec2 noise = get_ao_noise();
- vec2 area = get_ao_area(vP.z, radius);
vec2 dir = get_ao_dir(noise.x);
vec2 uv = get_uvs_from_view(vP);
vec3 vI = ((ProjectionMatrix[3][3] == 0.0) ? normalize(-vP) : vec3(0.0, 0.0, 1.0));
@@ -151,22 +150,22 @@ OcclusionData occlusion_search(
NO_OCCLUSION_DATA;
for (int i = 0; i < 2; i++) {
- /* View > NDC > Uv space. */
- vec2 uv_dir = dir * area * 0.5;
- /* Offset the start one pixel to avoid self shadowing. */
- /* TODO(fclem) Using DDA line algo should fix this. */
- vec2 px_dir = uv_dir * textureSize(depth_tx, 0);
- float max_px_dir = max_v2(abs(px_dir));
- vec2 uv_ofs = (px_dir / max_px_dir) / textureSize(depth_tx, 0);
- /* No need to trace more. */
- uv_dir -= uv_ofs;
-
- if (max_px_dir > 1.0) {
- data.horizons[0 + i * 2] = search_horizon(
- vI, vP, noise.y, uv + uv_ofs, uv_dir, depth_tx, inverted, radius, dir_sample_count);
- data.horizons[1 + i * 2] = -search_horizon(
- vI, vP, noise.y, uv - uv_ofs, -uv_dir, depth_tx, inverted, radius, dir_sample_count);
- }
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = vec3(dir * radius, 0.0);
+
+ ScreenSpaceRay ssray;
+
+ ssray = raytrace_screenspace_ray_create(ray);
+ data.horizons[0 + i * 2] = search_horizon(
+ vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count);
+
+ ray.direction = -ray.direction;
+
+ ssray = raytrace_screenspace_ray_create(ray);
+ data.horizons[1 + i * 2] = -search_horizon(
+ vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count);
+
/* Rotate 90 degrees. */
dir = vec2(-dir.y, dir.x);
}
@@ -196,6 +195,7 @@ void occlusion_eval(OcclusionData data,
vec3 Ng,
const float inverted,
out float visibility,
+ out float visibility_error,
out vec3 bent_normal)
{
if ((int(aoSettings) & USE_AO) == 0) {
@@ -222,6 +222,7 @@ void occlusion_eval(OcclusionData data,
vec2 noise = get_ao_noise();
vec2 dir = get_ao_dir(noise.x);
+ visibility_error = 0.0;
visibility = 0.0;
bent_normal = N * 0.001;
@@ -261,12 +262,17 @@ void occlusion_eval(OcclusionData data,
float a = dot(-cos(2.0 * h - angle_N) + N_cos + 2.0 * h * N_sin, vec2(0.25));
/* Correct normal not on plane (Eq. 8). */
visibility += proj_N_len * a;
+ /* Using a very low number of slices (2) leads to over-darkening of surfaces orthogonal to
+ * the view. This is particularly annoying for sharp reflections occlusion. So we compute how
+ * much the error is and correct the visibility later. */
+ visibility_error += proj_N_len;
/* Rotate 90 degrees. */
dir = vec2(-dir.y, dir.x);
}
/* We integrated 2 directions. */
visibility *= 0.5;
+ visibility_error *= 0.5;
visibility = min(visibility, data.custom_occlusion);
@@ -300,8 +306,9 @@ float gtao_multibounce(float visibility, vec3 albedo)
float diffuse_occlusion(OcclusionData data, vec3 V, vec3 N, vec3 Ng)
{
vec3 unused;
+ float unused_error;
float visibility;
- occlusion_eval(data, V, N, Ng, 0.0, visibility, unused);
+ occlusion_eval(data, V, N, Ng, 0.0, visibility, unused_error, unused);
/* Scale by user factor */
visibility = pow(saturate(visibility), aoFactor);
return visibility;
@@ -311,7 +318,8 @@ float diffuse_occlusion(
OcclusionData data, vec3 V, vec3 N, vec3 Ng, vec3 albedo, out vec3 bent_normal)
{
float visibility;
- occlusion_eval(data, V, N, Ng, 0.0, visibility, bent_normal);
+ float unused_error;
+ occlusion_eval(data, V, N, Ng, 0.0, visibility, unused_error, bent_normal);
visibility = gtao_multibounce(visibility, albedo);
/* Scale by user factor */
@@ -354,8 +362,12 @@ float specular_occlusion(
OcclusionData data, vec3 V, vec3 N, float roughness, inout vec3 specular_dir)
{
vec3 visibility_dir;
+ float visibility_error;
float visibility;
- occlusion_eval(data, V, N, N, 0.0, visibility, visibility_dir);
+ occlusion_eval(data, V, N, N, 0.0, visibility, visibility_error, visibility_dir);
+
+ /* Correct visibility error for very sharp surfaces. */
+ visibility *= mix(safe_rcp(visibility_error), 1.0, roughness);
specular_dir = normalize(mix(specular_dir, visibility_dir, roughness * (1.0 - visibility)));
@@ -371,7 +383,7 @@ float specular_occlusion(
float specular_solid_angle = spherical_cap_intersection(M_PI_2, spec_angle, cone_nor_dist);
float specular_occlusion = isect_solid_angle / specular_solid_angle;
/* Mix because it is unstable in unoccluded areas. */
- visibility = mix(isect_solid_angle / specular_solid_angle, 1.0, pow(visibility, 8.0));
+ visibility = mix(specular_occlusion, 1.0, pow(visibility, 8.0));
/* Scale by user factor */
visibility = pow(saturate(visibility), aoFactor);
@@ -389,7 +401,7 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion)
data = unpack_occlusion_data(texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0));
}
#else
- /* For blended surfaces and */
+ /* For blended surfaces. */
data = occlusion_search(vP, maxzBuffer, aoDistance, 0.0, 8.0);
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index bc2895ef3df..c8eaa06094e 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -102,7 +102,7 @@ float D_ggx_opti(float NH, float a2)
return M_PI * tmp * tmp; /* Doing RCP and mul a2 at the end */
}
-float G1_Smith_GGX(float NX, float a2)
+float G1_Smith_GGX_opti(float NX, float a2)
{
/* Using Brian Karis approach and refactoring by NX/NX
* this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV
@@ -122,7 +122,7 @@ float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness)
float NL = max(dot(N, L), 1e-8);
float NV = max(dot(N, V), 1e-8);
- float G = G1_Smith_GGX(NV, a2) * G1_Smith_GGX(NL, a2); /* Doing RCP at the end */
+ float G = G1_Smith_GGX_opti(NV, a2) * G1_Smith_GGX_opti(NL, a2); /* Doing RCP at the end */
float D = D_ggx_opti(NH, a2);
/* Denominator is canceled by G1_Smith */
@@ -135,6 +135,60 @@ void accumulate_light(vec3 light, float fac, inout vec4 accum)
accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a));
}
+/* Same thing as Cycles without the comments to make it shorter. */
+vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N)
+{
+ vec3 R = -reflect(I, N);
+
+ /* Reflection rays may always be at least as shallow as the incoming ray. */
+ float threshold = min(0.9 * dot(Ng, I), 0.025);
+ if (dot(Ng, R) >= threshold) {
+ return N;
+ }
+
+ float NdotNg = dot(N, Ng);
+ vec3 X = normalize(N - NdotNg * Ng);
+
+ float Ix = dot(I, X), Iz = dot(I, Ng);
+ float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
+ float a = Ix2 + Iz2;
+
+ float b = sqrt(Ix2 * (a - sqr(threshold)));
+ float c = Iz * threshold + a;
+
+ float fac = 0.5 / a;
+ float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c);
+ bool valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5));
+ bool valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5));
+
+ vec2 N_new;
+ if (valid1 && valid2) {
+ /* If both are possible, do the expensive reflection-based check. */
+ vec2 N1 = vec2(sqrt(1.0 - N1_z2), sqrt(N1_z2));
+ vec2 N2 = vec2(sqrt(1.0 - N2_z2), sqrt(N2_z2));
+
+ float R1 = 2.0 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz;
+ float R2 = 2.0 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz;
+
+ valid1 = (R1 >= 1e-5);
+ valid2 = (R2 >= 1e-5);
+ if (valid1 && valid2) {
+ N_new = (R1 < R2) ? N1 : N2;
+ }
+ else {
+ N_new = (R1 > R2) ? N1 : N2;
+ }
+ }
+ else if (valid1 || valid2) {
+ float Nz2 = valid1 ? N1_z2 : N2_z2;
+ N_new = vec2(sqrt(1.0 - Nz2), sqrt(Nz2));
+ }
+ else {
+ return Ng;
+ }
+ return N_new.x * X + N_new.y * Ng;
+}
+
/* ----------- Cone angle Approximation --------- */
/* Return a fitted cone angle given the input roughness */
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
index 46ea8b747c8..4c1544654c1 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
@@ -25,7 +25,8 @@ void main()
vec3 Xi = (vec3(i, j, 0.0) + 0.5) / sampleCount;
Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI));
- vec3 H = sample_ggx(Xi, a2); /* Microfacet normal */
+ /* Microfacet normal */
+ vec3 H = sample_ggx(Xi, a, V);
vec3 L = -reflect(V, H);
float NL = L.z;
@@ -33,9 +34,10 @@ void main()
float NH = max(H.z, 0.0);
float VH = max(dot(V, H), 0.0);
- float G1_v = G1_Smith_GGX(NV, a2);
- float G1_l = G1_Smith_GGX(NL, a2);
- float G_smith = 4.0 * NV * NL / (G1_v * G1_l); /* See G1_Smith_GGX for explanations. */
+ float G1_v = G1_Smith_GGX_opti(NV, a2);
+ float G1_l = G1_Smith_GGX_opti(NL, a2);
+ /* See G1_Smith_GGX_opti for explanations. */
+ float G_smith = 4.0 * NV * NL / (G1_v * G1_l);
float brdf = (G_smith * VH) / (NH * NV);
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
index 4abc313d7e3..7ce95a4aff2 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -1,89 +1,123 @@
-#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
-
-uniform sampler1D texHammersley;
-
-vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
-{
- return T * vector.x + B * vector.y + N * vector.z;
-}
+/**
+ * Sampling distribution routines for Monte-carlo integration.
+ **/
-#ifdef HAMMERSLEY_SIZE
-vec3 hammersley_3d(float i, float invsamplenbr)
-{
- vec3 Xi; /* Theta, cos(Phi), sin(Phi) */
-
- Xi.x = i * invsamplenbr;
- Xi.yz = texelFetch(texHammersley, int(i), 0).rg;
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
- return Xi;
-}
-#endif
+/* -------------------------------------------------------------------- */
+/** \name Microfacet GGX distribution
+ * \{ */
-/* -------------- BSDFS -------------- */
+#define USE_VISIBLE_NORMAL 1
-float pdf_ggx_reflect(float NH, float a2)
+float pdf_ggx_reflect(float NH, float NV, float VH, float alpha)
{
+ float a2 = sqr(alpha);
+#if USE_VISIBLE_NORMAL
+ float D = a2 / D_ggx_opti(NH, a2);
+ float G1 = NV * 2.0 / G1_Smith_GGX_opti(NV, a2);
+ return G1 * VH * D / NV;
+#else
return NH * a2 / D_ggx_opti(NH, a2);
+#endif
}
-float pdf_hemisphere()
-{
- return 0.5 * M_1_PI;
-}
-
-vec3 sample_ggx(vec3 rand, float a2)
+vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt)
{
+#if USE_VISIBLE_NORMAL
+ /* From:
+ * "A Simpler and Exact Sampling Routine for the GGXDistribution of Visible Normals"
+ * by Eric Heitz.
+ * http://jcgt.org/published/0007/04/01/slides.pdf
+ * View vector is expected to be in tangent space. */
+
+ /* Stretch view. */
+ vec3 Th, Bh, Vh = normalize(vec3(alpha * Vt.xy, Vt.z));
+ make_orthonormal_basis(Vh, Th, Bh);
+ /* Sample point with polar coordinates (r, phi). */
+ float r = sqrt(rand.x);
+ float x = r * rand.y;
+ float y = r * rand.z;
+ float s = 0.5 * (1.0 + Vh.z);
+ y = (1.0 - s) * sqrt(1.0 - x * x) + s * y;
+ float z = sqrt(saturate(1.0 - x * x - y * y));
+ /* Compute normal. */
+ vec3 Hh = x * Th + y * Bh + z * Vh;
+ /* Unstretch. */
+ vec3 Ht = normalize(vec3(alpha * Hh.xy, saturate(Hh.z)));
+ /* Microfacet Normal. */
+ return Ht;
+#else
/* Theta is the cone angle. */
- float z = sqrt((1.0 - rand.x) / (1.0 + a2 * rand.x - rand.x)); /* cos theta */
- float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
+ float z = sqrt((1.0 - rand.x) / (1.0 + sqr(alpha) * rand.x - rand.x)); /* cos theta */
+ float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
float x = r * rand.y;
float y = r * rand.z;
-
/* Microfacet Normal */
return vec3(x, y, z);
+#endif
}
-vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH)
+vec3 sample_ggx(vec3 rand, float alpha, vec3 V, vec3 N, vec3 T, vec3 B, out float pdf)
{
- vec3 Ht = sample_ggx(rand, a2);
- NH = Ht.z;
+ vec3 Vt = world_to_tangent(V, N, T, B);
+ vec3 Ht = sample_ggx(rand, alpha, Vt);
+ float NH = saturate(Ht.z);
+ float NV = saturate(Vt.z);
+ float VH = saturate(dot(Vt, Ht));
+ pdf = pdf_ggx_reflect(NH, NV, VH, alpha);
return tangent_to_world(Ht, N, T, B);
}
-#ifdef HAMMERSLEY_SIZE
-vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Uniform Hemisphere
+ * \{ */
+
+float pdf_uniform_hemisphere()
{
- vec3 Xi = hammersley_3d(nsample, inv_sample_count);
- vec3 Ht = sample_ggx(Xi, a2);
- return tangent_to_world(Ht, N, T, B);
+ return 0.5 * M_1_PI;
}
-vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B)
+vec3 sample_uniform_hemisphere(vec3 rand)
{
- vec3 Xi = hammersley_3d(nsample, inv_sample_count);
-
- float z = Xi.x; /* cos theta */
- float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
- float x = r * Xi.y;
- float y = r * Xi.z;
-
- vec3 Ht = vec3(x, y, z);
+ float z = rand.x; /* cos theta */
+ float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
+ float x = r * rand.y;
+ float y = r * rand.z;
+ return vec3(x, y, z);
+}
+vec3 sample_uniform_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B, out float pdf)
+{
+ vec3 Ht = sample_uniform_hemisphere(rand);
+ pdf = pdf_uniform_hemisphere();
return tangent_to_world(Ht, N, T, B);
}
-vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec3 T, vec3 B)
-{
- vec3 Xi = hammersley_3d(nsample, inv_sample_count);
+/** \} */
- float z = cos(angle * Xi.x); /* cos theta */
- float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
- float x = r * Xi.y;
- float y = r * Xi.z;
+/* -------------------------------------------------------------------- */
+/** \name Uniform Cone sampling
+ * \{ */
- vec3 Ht = vec3(x, y, z);
+vec3 sample_uniform_cone(vec3 rand, float angle)
+{
+ float z = cos(angle * rand.x); /* cos theta */
+ float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
+ float x = r * rand.y;
+ float y = r * rand.z;
+ return vec3(x, y, z);
+}
+vec3 sample_uniform_cone(vec3 rand, float angle, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Ht = sample_uniform_cone(rand, angle);
+ /* TODO pdf? */
return tangent_to_world(Ht, N, T, B);
}
-#endif
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
index 2ffe23a9197..2f1298e2707 100644
--- a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
@@ -37,7 +37,7 @@ void main()
Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI));
/* Microfacet normal. */
- vec3 H = sample_ggx(Xi, a2);
+ vec3 H = sample_ggx(Xi, a2, V);
float VH = dot(V, H);
@@ -59,7 +59,7 @@ void main()
float LH = dot(L, H);
/* Balancing the adjustments made in G1_Smith. */
- float G1_l = NL * 2.0 / G1_Smith_GGX(NL, a2);
+ float G1_l = NL * 2.0 / G1_Smith_GGX_opti(NL, a2);
/* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
* pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
index 5c10a7f451f..00d265a48b0 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
@@ -3,6 +3,7 @@
#pragma BLENDER_REQUIRE(lights_lib.glsl)
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
struct ClosureInputGlossy {
vec3 N; /** Shading normal. */
@@ -39,6 +40,10 @@ ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
cl_out.radiance = vec3(0.0);
+#ifndef STEP_RESOLVE /* SSR */
+ cl_in.N = ensure_valid_reflection(cl_common.Ng, cl_common.V, cl_in.N);
+#endif
+
float NV = dot(cl_in.N, cl_common.V);
vec2 lut_uv = lut_coords(NV, cl_in.roughness);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
index 93492762bbe..b554fd113df 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
@@ -187,8 +187,6 @@ struct ClosureEvalCommon {
float specular_accum;
/** Diffuse probe accumulator. */
float diffuse_accum;
- /** Viewspace depth to start raytracing from. */
- float tracing_depth;
};
/* Common cl_out struct used by most closures. */
@@ -210,18 +208,6 @@ ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
cl_eval.vP = viewPosition;
cl_eval.Ng = safe_normalize(cross(dFdx(cl_eval.P), dFdy(cl_eval.P)));
cl_eval.vNg = transform_direction(ViewMatrix, cl_eval.Ng);
- /* TODO(fclem) See if we can avoid this complicated setup. */
-#ifdef STEP_RESOLVE /* SSR */
- cl_eval.tracing_depth = FragDepth;
-#else
- cl_eval.tracing_depth = gl_FragCoord.z;
-#endif
- /* Constant bias (due to depth buffer precision) */
- /* Magic numbers for 24bits of precision.
- * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
- cl_eval.tracing_depth -= mix(2.4e-7, 4.8e-7, cl_eval.tracing_depth);
- /* Convert to view Z. */
- cl_eval.tracing_depth = get_view_z_from_depth(cl_eval.tracing_depth);
cl_eval.occlusion_data = occlusion_load(cl_eval.vP, cl_in.occlusion);
@@ -254,13 +240,8 @@ ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_
light.L.w = length(light.L.xyz);
light.vis = light_visibility(light.data, cl_common.P, light.L);
- light.contact_shadow = light_contact_shadows(light.data,
- cl_common.P,
- cl_common.vP,
- cl_common.tracing_depth,
- cl_common.vNg,
- cl_common.rand.x,
- light.vis);
+ light.contact_shadow = light_contact_shadows(
+ light.data, cl_common.P, cl_common.vP, cl_common.vNg, cl_common.rand.x, light.vis);
return light;
}
diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
index a6c9eebaff2..b3174afc799 100644
--- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
@@ -2,7 +2,7 @@
layout(std140) uniform common_block
{
mat4 pastViewProjectionMatrix;
- vec2 mipRatio[10]; /* To correct mip level texel misalignment */
+ vec4 hizUvScale; /* To correct mip level texel misalignment */
/* Ambient Occlusion */
vec4 aoParameters[2];
/* Volumetric */
@@ -37,15 +37,15 @@ layout(std140) uniform common_block
int prbIrradianceVisSize;
float prbIrradianceSmooth;
float prbLodCubeMax;
- float prbLodPlanarMax;
/* Misc*/
- int hizMipOffset;
int rayType;
float rayDepth;
float alphaHashOffset;
float alphaHashScale;
+ float pad6;
float pad7;
float pad8;
+ float pad9;
};
/* rayType (keep in sync with ray_type) */
@@ -70,8 +70,4 @@ layout(std140) uniform common_block
#define ssrThickness ssrParameters.y
#define ssrPixelSize ssrParameters.zw
-vec2 mip_ratio_interp(float mip)
-{
- float low_mip = floor(mip);
- return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip);
-}
+#define ssrUvScale hizUvScale.zw
diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
index 33d7347a377..c6f61d1d443 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
@@ -26,6 +26,8 @@
* THE SOFTWARE.
*/
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform sampler2D sourceBuffer; /* Buffer to filter */
uniform vec2 sourceBufferTexelSize;
@@ -54,11 +56,6 @@ vec3 safe_color(vec3 c)
return clamp(c, vec3(0.0), vec3(1e20)); /* 1e20 arbitrary. */
}
-float brightness(vec3 c)
-{
- return max(max(c.r, c.g), c.b);
-}
-
/* 3-tap median filter */
vec3 median(vec3 a, vec3 b, vec3 c)
{
@@ -78,10 +75,10 @@ vec3 downsample_filter_high(sampler2D tex, vec2 uv, vec2 texelSize)
vec3 s4 = textureLod(tex, uv + d.zw, 0.0).rgb;
/* Karis's luma weighted average (using brightness instead of luma) */
- float s1w = 1.0 / (brightness(s1) + 1.0);
- float s2w = 1.0 / (brightness(s2) + 1.0);
- float s3w = 1.0 / (brightness(s3) + 1.0);
- float s4w = 1.0 / (brightness(s4) + 1.0);
+ float s1w = 1.0 / (max_v3(s1) + 1.0);
+ float s2w = 1.0 / (max_v3(s2) + 1.0);
+ float s3w = 1.0 / (max_v3(s3) + 1.0);
+ float s4w = 1.0 / (max_v3(s4) + 1.0);
float one_div_wsum = 1.0 / (s1w + s2w + s3w + s4w);
return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum;
@@ -156,7 +153,7 @@ vec4 step_blit(void)
#endif
/* Pixel brightness */
- float br = brightness(m);
+ float br = max_v3(m);
/* Under-threshold part: quadratic curve */
float rq = clamp(br - curveThreshold.x, 0, curveThreshold.y);
@@ -167,7 +164,7 @@ vec4 step_blit(void)
/* Clamp pixel intensity if clamping enabled */
if (clampIntensity > 0.0) {
- br = max(1e-5, brightness(m));
+ br = max(1e-5, max_v3(m));
m *= 1.0 - max(0.0, br - clampIntensity) / br;
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl
index 88d83cd913a..3ad3c90d27a 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl
@@ -62,12 +62,6 @@ const vec2 quad_offsets[4] = vec2[4](
#define dof_coc_from_zdepth(d) calculate_coc(linear_depth(d))
-vec4 safe_color(vec4 c)
-{
- /* Clamp to avoid black square artifacts if a pixel goes NaN. */
- return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
-}
-
float dof_hdr_color_weight(vec4 color)
{
/* From UE4. Very fast "luma" weighting. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl
index 0ac1cda9e3d..05f16b866e0 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl
@@ -2,6 +2,8 @@
* Simple down-sample shader. Takes the average of the 4 texels of lower mip.
*/
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform samplerCube source;
uniform float texelSize;
@@ -28,11 +30,6 @@ const vec3 y_axis[6] = vec3[6](vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0));
-float brightness(vec3 c)
-{
- return max(max(c.r, c.g), c.b);
-}
-
void main()
{
vec2 uvs = gl_FragCoord.xy * texelSize;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
index a4637b9df91..d1cb25af82f 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
@@ -1,5 +1,9 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
/**
- * Simple down-sample shader. Takes the average of the 4 texels of lower mip.
+ * Simple down-sample shader.
+ * Do a gaussian filter using 4 bilinear texture samples.
*/
uniform sampler2D source;
@@ -7,31 +11,27 @@ uniform float fireflyFactor;
out vec4 FragColor;
-float brightness(vec3 c)
-{
- return max(max(c.r, c.g), c.b);
-}
-
void main()
{
-#if 0
- /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
- vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+ vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
+ vec2 uvs = gl_FragCoord.xy * texel_size;
+#ifdef COPY_SRC
FragColor = textureLod(source, uvs, 0.0);
+ FragColor = safe_color(FragColor);
+
+ /* Clamped brightness. */
+ float luma = max(1e-8, max_v3(FragColor.rgb));
+ FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
+
#else
- vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
- vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size;
vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75);
+ uvs *= 2.0;
FragColor = textureLod(source, uvs + ofs.xy, 0.0);
FragColor += textureLod(source, uvs + ofs.xw, 0.0);
FragColor += textureLod(source, uvs + ofs.zy, 0.0);
FragColor += textureLod(source, uvs + ofs.zw, 0.0);
FragColor *= 0.25;
-
- /* Clamped brightness. */
- float luma = max(1e-8, brightness(FragColor.rgb));
- FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
index 19ae0acc443..70f1e9f1e66 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
@@ -10,21 +10,11 @@
* The final integration is done at the resolve stage with the shading normal.
*/
+in vec4 uvcoordsvar;
+
out vec4 FragColor;
uniform sampler2D normalBuffer;
-#ifdef LAYERED_DEPTH
-uniform sampler2DArray depthBufferLayered;
-uniform int layer;
-# define gtao_depthBuffer depthBufferLayered
-# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c)
-
-#else
-uniform sampler2D depthBuffer;
-# define gtao_depthBuffer depthBuffer
-# define gtao_textureLod(a, b, c) textureLod(a, b, c)
-
-#endif
/* Similar to https://atyuwen.github.io/posts/normal-reconstruction/.
* This samples the depth buffer 4 time for each direction to get the most correct
@@ -36,10 +26,10 @@ vec3 view_position_derivative_from_depth(vec2 uvs, vec2 ofs, vec3 vP, float dept
vec2 uv3 = uvs + ofs;
vec2 uv4 = uvs + ofs * 2.0;
vec4 H;
- H.x = gtao_textureLod(gtao_depthBuffer, uv1, 0.0).r;
- H.y = gtao_textureLod(gtao_depthBuffer, uv2, 0.0).r;
- H.z = gtao_textureLod(gtao_depthBuffer, uv3, 0.0).r;
- H.w = gtao_textureLod(gtao_depthBuffer, uv4, 0.0).r;
+ H.x = textureLod(maxzBuffer, uv1, 0.0).r;
+ H.y = textureLod(maxzBuffer, uv2, 0.0).r;
+ H.z = textureLod(maxzBuffer, uv3, 0.0).r;
+ H.w = textureLod(maxzBuffer, uv4, 0.0).r;
/* Fix issue with depth precision. Take even larger diff. */
vec4 diff = abs(vec4(depth_center, H.yzw) - H.x);
if (max_v4(diff) < 2.4e-7 && all(lessThan(diff.xyz, diff.www))) {
@@ -56,16 +46,10 @@ vec3 view_position_derivative_from_depth(vec2 uvs, vec2 ofs, vec3 vP, float dept
}
/* TODO(fclem) port to a common place for other effects to use. */
-bool reconstruct_view_position_and_normal_from_depth(vec2 texel, out vec3 vP, out vec3 vNg)
+bool reconstruct_view_position_and_normal_from_depth(vec2 uvs, out vec3 vP, out vec3 vNg)
{
- vec2 texel_size = 1.0 / vec2(textureSize(gtao_depthBuffer, 0).xy);
- vec2 uvs = gl_FragCoord.xy * texel_size;
- float depth_center = gtao_textureLod(gtao_depthBuffer, uvs, 0.0).r;
-
- /* Background case. */
- if (depth_center == 1.0) {
- return false;
- }
+ vec2 texel_size = vec2(abs(dFdx(uvs.x)), abs(dFdy(uvs.y)));
+ float depth_center = textureLod(maxzBuffer, uvs, 0.0).r;
vP = get_view_space_from_depth(uvs, depth_center);
@@ -74,18 +58,22 @@ bool reconstruct_view_position_and_normal_from_depth(vec2 texel, out vec3 vP, ou
vNg = safe_normalize(cross(dPdx, dPdy));
+ /* Background case. */
+ if (depth_center == 1.0) {
+ return false;
+ }
+
return true;
}
#ifdef DEBUG_AO
-in vec4 uvcoordsvar;
-
void main()
{
vec3 vP, vNg;
+ vec2 uvs = uvcoordsvar.xy;
- if (!reconstruct_view_position_and_normal_from_depth(gl_FragCoord.xy, vP, vNg)) {
+ if (!reconstruct_view_position_and_normal_from_depth(uvs * hizUvScale.xy, vP, vNg)) {
/* Handle Background case. Prevent artifact due to uncleared Horizon Render Target. */
FragColor = vec4(0.0);
}
@@ -93,15 +81,18 @@ void main()
vec3 P = transform_point(ViewMatrixInverse, vP);
vec3 V = cameraVec(P);
vec3 vV = viewCameraVec(vP);
- vec3 vN = normal_decode(texture(normalBuffer, uvcoordsvar.xy).rg, vV);
+ vec3 vN = normal_decode(texture(normalBuffer, uvs).rg, vV);
vec3 N = transform_direction(ViewMatrixInverse, vN);
vec3 Ng = transform_direction(ViewMatrixInverse, vNg);
OcclusionData data = occlusion_load(vP, 1.0);
- float visibility = diffuse_occlusion(data, V, N, Ng);
-
- FragColor = vec4(visibility);
+ if (min_v4(abs(data.horizons)) != M_PI) {
+ FragColor = vec4(diffuse_occlusion(data, V, N, Ng));
+ }
+ else {
+ FragColor = vec4(1.0);
+ }
}
}
@@ -109,8 +100,8 @@ void main()
void main()
{
- vec2 uvs = gl_FragCoord.xy / vec2(textureSize(gtao_depthBuffer, 0).xy);
- float depth = gtao_textureLod(gtao_depthBuffer, uvs, 0.0).r;
+ vec2 uvs = uvcoordsvar.xy;
+ float depth = textureLod(maxzBuffer, uvs * hizUvScale.xy, 0.0).r;
vec3 vP = get_view_space_from_depth(uvs, depth);
OcclusionData data = NO_OCCLUSION_DATA;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
index b99037b1e80..ccb65d2e5a6 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -2,6 +2,9 @@
* Shader that down-sample depth buffer,
* saving min and max value of each texel in the above mipmaps.
* Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/
+ *
+ * Major simplification has been made since we pad the buffer to always be bigger than input to
+ * avoid mipmapping misalignement.
*/
#ifdef LAYERED
@@ -12,10 +15,10 @@ uniform sampler2D depthBuffer;
#endif
#ifdef LAYERED
-# define sampleLowerMip(t) texelFetch(depthBuffer, ivec3(t, depthLayer), 0).r
+# define sampleLowerMip(t) texture(depthBuffer, vec3(t, depthLayer)).r
# define gatherLowerMip(t) textureGather(depthBuffer, vec3(t, depthLayer))
#else
-# define sampleLowerMip(t) texelFetch(depthBuffer, t, 0).r
+# define sampleLowerMip(t) texture(depthBuffer, t).r
# define gatherLowerMip(t) textureGather(depthBuffer, t)
#endif
@@ -37,54 +40,27 @@ out vec4 fragColor;
void main()
{
- ivec2 texelPos = ivec2(gl_FragCoord.xy);
- ivec2 mipsize = textureSize(depthBuffer, 0).xy;
-
-#ifndef COPY_DEPTH
- texelPos *= 2;
-#endif
+ vec2 texel = gl_FragCoord.xy;
+ vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy);
#ifdef COPY_DEPTH
- float val = sampleLowerMip(texelPos);
+ vec2 uv = texel * texel_size;
+
+ float val = sampleLowerMip(uv);
#else
+ vec2 uv = texel * 2.0 * texel_size;
+
vec4 samp;
# ifdef GPU_ARB_texture_gather
- /* + 1.0 to gather at the center of target 4 texels. */
- samp = gatherLowerMip((vec2(texelPos) + 1.0) / vec2(mipsize));
+ samp = gatherLowerMip(uv);
# else
- samp.x = sampleLowerMip(texelPos);
- samp.y = sampleLowerMip(texelPos + ivec2(1, 0));
- samp.z = sampleLowerMip(texelPos + ivec2(1, 1));
- samp.w = sampleLowerMip(texelPos + ivec2(0, 1));
+ samp.x = sampleLowerMip(uv + vec2(-0.5, -0.5) * texel_size);
+ samp.y = sampleLowerMip(uv + vec2(-0.5, 0.5) * texel_size);
+ samp.z = sampleLowerMip(uv + vec2(0.5, -0.5) * texel_size);
+ samp.w = sampleLowerMip(uv + vec2(0.5, 0.5) * texel_size);
# endif
float val = minmax4(samp.x, samp.y, samp.z, samp.w);
-
- /* if we are reducing an odd-width texture then fetch the edge texels */
- if (((mipsize.x & 1) != 0) && (texelPos.x == mipsize.x - 3)) {
- /* if both edges are odd, fetch the top-left corner texel */
- if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) {
- samp.x = sampleLowerMip(texelPos + ivec2(2, 2));
- val = minmax2(val, samp.x);
- }
-# ifdef GPU_ARB_texture_gather
- samp = gatherLowerMip((vec2(texelPos) + vec2(2.0, 1.0)) / vec2(mipsize));
-# else
- samp.y = sampleLowerMip(texelPos + ivec2(2, 0));
- samp.z = sampleLowerMip(texelPos + ivec2(2, 1));
-# endif
- val = minmax3(val, samp.y, samp.z);
- }
- /* if we are reducing an odd-height texture then fetch the edge texels */
- if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) {
-# ifdef GPU_ARB_texture_gather
- samp = gatherLowerMip((vec2(texelPos) + vec2(1.0, 2.0)) / vec2(mipsize));
-# else
- samp.x = sampleLowerMip(texelPos + ivec2(0, 2));
- samp.y = sampleLowerMip(texelPos + ivec2(1, 2));
-# endif
- val = minmax3(val, samp.x, samp.y);
- }
#endif
#if defined(GPU_INTEL) || defined(GPU_ATI)
diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_lib.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_lib.glsl
new file mode 100644
index 00000000000..cc73bbbfe29
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_lib.glsl
@@ -0,0 +1,101 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+/* Based on:
+ * "Stochastic Screen Space Reflections"
+ * by Tomasz Stachowiak.
+ * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections
+ * and
+ * "Stochastic all the things: raytracing in hybrid real-time rendering"
+ * by Tomasz Stachowiak.
+ * https://media.contentapi.ea.com/content/dam/ea/seed/presentations/dd18-seed-raytracing-in-hybrid-real-time-rendering.pdf
+ */
+
+uniform ivec2 halfresOffset;
+
+struct HitData {
+ /** Hit direction scaled by intersection time. */
+ vec3 hit_dir;
+ /** Screen space [0..1] depth of the reflection hit position, or -1.0 for planar reflections. */
+ float hit_depth;
+ /** Inverse probability of ray spawning in this direction. */
+ float ray_pdf_inv;
+ /** True if ray has hit valid geometry. */
+ bool is_hit;
+ /** True if ray was generated from a planar reflection probe. */
+ bool is_planar;
+};
+
+void encode_hit_data(HitData data, vec3 hit_sP, vec3 vP, out vec4 hit_data, out float hit_depth)
+{
+ vec3 hit_vP = get_view_space_from_depth(hit_sP.xy, hit_sP.z);
+ hit_data.xyz = hit_vP - vP;
+ hit_depth = data.is_planar ? -1.0 : hit_sP.z;
+ /* Record 1.0 / pdf to reduce the computation in the resolve phase. */
+ /* Encode hit validity in sign. */
+ hit_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0);
+}
+
+HitData decode_hit_data(vec4 hit_data, float hit_depth)
+{
+ HitData data;
+ data.hit_dir.xyz = hit_data.xyz;
+ data.hit_depth = hit_depth;
+ data.is_planar = (hit_depth == -1.0);
+ data.ray_pdf_inv = abs(hit_data.w);
+ data.is_hit = (hit_data.w > 0.0);
+ return data;
+}
+
+/* Blue noise categorised into 4 sets of samples.
+ * See "Stochastic all the things" presentation slide 32-37. */
+const int resolve_samples_count = 9;
+const vec2 resolve_sample_offsets[36] = vec2[36](
+ /* Set 1. */
+ /* First Ring (2x2). */
+ vec2(0, 0),
+ /* Second Ring (6x6). */
+ vec2(-1, 3),
+ vec2(1, 3),
+ vec2(-1, 1),
+ vec2(3, 1),
+ vec2(-2, 0),
+ vec2(3, 0),
+ vec2(2, -1),
+ vec2(1, -2),
+ /* Set 2. */
+ /* First Ring (2x2). */
+ vec2(1, 1),
+ /* Second Ring (6x6). */
+ vec2(-2, 3),
+ vec2(3, 3),
+ vec2(0, 2),
+ vec2(2, 2),
+ vec2(-2, -1),
+ vec2(1, -1),
+ vec2(0, -2),
+ vec2(3, -2),
+ /* Set 3. */
+ /* First Ring (2x2). */
+ vec2(0, 1),
+ /* Second Ring (6x6). */
+ vec2(0, 3),
+ vec2(3, 2),
+ vec2(-2, 1),
+ vec2(2, 1),
+ vec2(-1, 0),
+ vec2(-2, -2),
+ vec2(0, -1),
+ vec2(2, -2),
+ /* Set 4. */
+ /* First Ring (2x2). */
+ vec2(1, 0),
+ /* Second Ring (6x6). */
+ vec2(2, 3),
+ vec2(-2, 2),
+ vec2(-1, 2),
+ vec2(1, 2),
+ vec2(2, 0),
+ vec2(-1, -1),
+ vec2(3, -1),
+ vec2(-1, -2)); \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl
new file mode 100644
index 00000000000..6f2619127e3
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl
@@ -0,0 +1,220 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+#pragma BLENDER_REQUIRE(effect_reflection_lib.glsl)
+
+/* Based on:
+ * "Stochastic Screen Space Reflections"
+ * by Tomasz Stachowiak.
+ * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections
+ * and
+ * "Stochastic all the things: raytracing in hybrid real-time rendering"
+ * by Tomasz Stachowiak.
+ * https://media.contentapi.ea.com/content/dam/ea/seed/presentations/dd18-seed-raytracing-in-hybrid-real-time-rendering.pdf
+ */
+
+uniform sampler2D colorBuffer;
+uniform sampler2D normalBuffer;
+uniform sampler2D specroughBuffer;
+uniform sampler2D hitBuffer;
+uniform sampler2D hitDepth;
+
+uniform int samplePoolOffset;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+vec4 ssr_get_scene_color_and_mask(vec3 hit_vP, int planar_index, float mip)
+{
+ vec2 uv;
+ if (planar_index != -1) {
+ uv = get_uvs_from_view(hit_vP);
+ /* Planar X axis is flipped. */
+ uv.x = 1.0 - uv.x;
+ }
+ else {
+ /* Find hit position in previous frame. */
+ /* TODO Combine matrices. */
+ vec3 hit_P = transform_point(ViewMatrixInverse, hit_vP);
+ /* TODO real reprojection with motion vectors, etc... */
+ uv = project_point(pastViewProjectionMatrix, hit_P).xy * 0.5 + 0.5;
+ }
+
+ vec3 color;
+ if (planar_index != -1) {
+ color = textureLod(probePlanars, vec3(uv, planar_index), mip).rgb;
+ }
+ else {
+ color = textureLod(colorBuffer, uv * hizUvScale.xy, mip).rgb;
+ }
+
+ /* Clamped brightness. */
+ float luma = max_v3(color);
+ color *= 1.0 - max(0.0, luma - ssrFireflyFac) * safe_rcp(luma);
+
+ float mask = screen_border_mask(uv);
+ return vec4(color, mask);
+}
+
+void resolve_reflection_sample(int planar_index,
+ vec2 sample_uv,
+ vec3 vP,
+ vec3 vN,
+ vec3 vV,
+ float roughness_squared,
+ float cone_tan,
+ inout float weight_accum,
+ inout vec4 ssr_accum)
+{
+ vec4 hit_data = texture(hitBuffer, sample_uv);
+ float hit_depth = texture(hitDepth, sample_uv).r;
+ HitData data = decode_hit_data(hit_data, hit_depth);
+
+ float hit_dist = length(data.hit_dir);
+
+ /* Slide 54. */
+ float bsdf = bsdf_ggx(vN, data.hit_dir / hit_dist, vV, roughness_squared);
+
+ float weight = bsdf * data.ray_pdf_inv;
+
+ /* Do not reuse hitpoint from planar reflections for normal reflections and vice versa. */
+ if ((planar_index == -1 && data.is_planar) || (planar_index != -1 && !data.is_planar)) {
+ return;
+ }
+ /* Do not add light if ray has failed but still weight it. */
+ if (!data.is_hit) {
+ weight_accum += weight;
+ return;
+ }
+
+ vec3 hit_vP = vP + data.hit_dir;
+
+ /* Compute cone footprint in screen space. */
+ float cone_footprint = hit_dist * cone_tan;
+ float homcoord = ProjectionMatrix[2][3] * hit_vP.z + ProjectionMatrix[3][3];
+ cone_footprint *= max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord;
+ cone_footprint *= ssrBrdfBias * 0.5;
+ /* Estimate a cone footprint to sample a corresponding mipmap level. */
+ float mip = log2(cone_footprint * max_v2(vec2(textureSize(specroughBuffer, 0))));
+
+ vec4 radiance_mask = ssr_get_scene_color_and_mask(hit_vP, planar_index, mip);
+
+ ssr_accum += radiance_mask * weight;
+ weight_accum += weight;
+}
+
+void raytrace_resolve(ClosureInputGlossy cl_in,
+ inout ClosureEvalGlossy cl_eval,
+ inout ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out)
+{
+ float roughness = cl_in.roughness;
+
+ vec4 ssr_accum = vec4(0.0);
+ float weight_acc = 0.0;
+
+ if (roughness < ssrMaxRoughness + 0.2) {
+ /* Find Planar Reflections affecting this pixel */
+ int planar_index = -1;
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
+ float fade = probe_attenuation_planar(planars_data[i], cl_common.P);
+ fade *= probe_attenuation_planar_normal_roughness(planars_data[i], cl_in.N, 0.0);
+ if (fade > 0.5) {
+ planar_index = i;
+ break;
+ }
+ }
+
+ vec3 V, P, N;
+ if (planar_index != -1) {
+ PlanarData pd = planars_data[planar_index];
+ /* Evaluate everything in refected space. */
+ P = line_plane_intersect(cl_common.P, cl_common.V, pd.pl_plane_eq);
+ V = reflect(cl_common.V, pd.pl_normal);
+ N = reflect(cl_in.N, pd.pl_normal);
+ }
+ else {
+ V = cl_common.V;
+ P = cl_common.P;
+ N = cl_in.N;
+ }
+
+ /* Using view space */
+ vec3 vV = transform_direction(ViewMatrix, cl_common.V);
+ vec3 vP = transform_point(ViewMatrix, cl_common.P);
+ vec3 vN = transform_direction(ViewMatrix, cl_in.N);
+
+ float roughness_squared = max(1e-3, sqr(roughness));
+ float cone_cos = cone_cosine(roughness_squared);
+ float cone_tan = sqrt(1.0 - cone_cos * cone_cos) / cone_cos;
+ cone_tan *= mix(saturate(dot(vN, -vV) * 2.0), 1.0, roughness); /* Elongation fit */
+
+ int sample_pool = int((uint(gl_FragCoord.x) & 1u) + (uint(gl_FragCoord.y) & 1u) * 2u);
+ sample_pool = (sample_pool + (samplePoolOffset / 5)) % 4;
+
+ for (int i = 0; i < resolve_samples_count; i++) {
+ int sample_id = sample_pool * resolve_samples_count + i;
+ vec2 texture_size = vec2(textureSize(hitBuffer, 0));
+ vec2 sample_texel = texture_size * uvcoordsvar.xy * ssrUvScale;
+ vec2 sample_uv = (sample_texel + resolve_sample_offsets[sample_id]) / texture_size;
+
+ resolve_reflection_sample(
+ planar_index, sample_uv, vP, vN, vV, roughness_squared, cone_tan, weight_acc, ssr_accum);
+ }
+ }
+
+ /* Compute SSR contribution */
+ ssr_accum *= safe_rcp(weight_acc);
+ /* fade between 0.5 and 1.0 roughness */
+ ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
+
+ cl_eval.raytrace_radiance = ssr_accum.rgb * ssr_accum.a;
+ cl_common.specular_accum -= ssr_accum.a;
+}
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy)
+
+void main()
+{
+ float depth = textureLod(maxzBuffer, uvcoordsvar.xy * hizUvScale.xy, 0.0).r;
+
+ if (depth == 1.0) {
+ discard;
+ }
+
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba;
+ vec3 brdf = speccol_roughness.rgb;
+ float roughness = speccol_roughness.a;
+
+ if (max_v3(brdf) <= 0.0) {
+ discard;
+ }
+
+ FragDepth = depth;
+
+ viewPosition = get_view_space_from_depth(uvcoordsvar.xy, depth);
+ worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+
+ vec2 normal_encoded = texelFetch(normalBuffer, texel, 0).rg;
+ viewNormal = normal_decode(normal_encoded, viewCameraVec(viewPosition));
+ worldNormal = transform_direction(ViewMatrixInverse, viewNormal);
+
+ CLOSURE_VARS_DECLARE_1(Glossy);
+
+ in_Glossy_0.N = worldNormal;
+ in_Glossy_0.roughness = roughness;
+
+ /* Do a full deferred evaluation of the glossy BSDF. The only difference is that we inject the
+ * SSR resolve before the cubemap iter. BRDF term is already computed during main pass and is
+ * passed as specular color. */
+ CLOSURE_EVAL_FUNCTION_1(ssr_resolve, Glossy);
+
+ fragColor = vec4(out_Glossy_0.radiance * brdf, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
new file mode 100644
index 00000000000..b1f17cb7b07
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
@@ -0,0 +1,149 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
+#pragma BLENDER_REQUIRE(effect_reflection_lib.glsl)
+
+/* Based on:
+ * "Stochastic Screen Space Reflections"
+ * by Tomasz Stachowiak.
+ * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections
+ * and
+ * "Stochastic all the things: raytracing in hybrid real-time rendering"
+ * by Tomasz Stachowiak.
+ * https://media.contentapi.ea.com/content/dam/ea/seed/presentations/dd18-seed-raytracing-in-hybrid-real-time-rendering.pdf
+ */
+
+uniform sampler2D normalBuffer;
+uniform sampler2D specroughBuffer;
+uniform vec2 targetSize;
+uniform float randomScale;
+
+in vec4 uvcoordsvar;
+
+layout(location = 0) out vec4 hitData;
+layout(location = 1) out float hitDepth;
+
+void main()
+{
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ /* Decorrelate from AA. */
+ /* TODO(fclem) we should use a more general approach for more random number dimensions. */
+ vec2 random_px = floor(fract(rand.xy * 2.2074408460575947536) * 1.99999) - 0.5;
+ rand.xy = fract(rand.xy * 3.2471795724474602596);
+
+ /* Randomly choose the pixel to start the ray from when tracing at lower resolution.
+ * This method also make sure we always start from the center of a fullres texel. */
+ vec2 uvs = (gl_FragCoord.xy + random_px * randomScale) / (targetSize * ssrUvScale);
+
+ float depth = textureLod(maxzBuffer, uvs * hizUvScale.xy, 0.0).r;
+
+ HitData data;
+ data.is_planar = false;
+ data.ray_pdf_inv = 0.0;
+ data.is_hit = false;
+ data.hit_dir = vec3(0.0, 0.0, 0.0);
+ /* Default: not hits. */
+ encode_hit_data(data, data.hit_dir, data.hit_dir, hitData, hitDepth);
+
+ /* Early out */
+ /* We can't do discard because we don't clear the render target. */
+ if (depth == 1.0) {
+ return;
+ }
+
+ /* Using view space */
+ vec3 vP = get_view_space_from_depth(uvs, depth);
+ vec3 P = transform_point(ViewMatrixInverse, vP);
+ vec3 vV = viewCameraVec(vP);
+ vec3 V = cameraVec(P);
+ vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV);
+ vec3 N = transform_direction(ViewMatrixInverse, vN);
+
+ /* Retrieve pixel data */
+ vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba;
+
+ /* Early out */
+ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
+ return;
+ }
+
+ float roughness = speccol_roughness.a;
+ float alpha = max(1e-3, roughness * roughness);
+
+ /* Early out */
+ if (roughness > ssrMaxRoughness + 0.2) {
+ return;
+ }
+
+ /* Planar Reflections */
+ int planar_id = -1;
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
+ PlanarData pd = planars_data[i];
+
+ float fade = probe_attenuation_planar(pd, P);
+ fade *= probe_attenuation_planar_normal_roughness(pd, N, 0.0);
+
+ if (fade > 0.5) {
+ /* Find view vector / reflection plane intersection. */
+ /* TODO optimize, use view space for all. */
+ vec3 P_plane = line_plane_intersect(P, V, pd.pl_plane_eq);
+ vP = transform_point(ViewMatrix, P_plane);
+
+ planar_id = i;
+ data.is_planar = true;
+ break;
+ }
+ }
+
+ /* Gives *perfect* reflection for very small roughness */
+ if (roughness < 0.04) {
+ rand.xzw *= 0.0;
+ }
+ /* Importance sampling bias */
+ rand.x = mix(rand.x, 0.0, ssrBrdfBias);
+
+ vec3 vT, vB;
+ make_orthonormal_basis(vN, vT, vB); /* Generate tangent space */
+
+ float pdf;
+ vec3 vH = sample_ggx(rand.xzw, alpha, vV, vN, vT, vB, pdf);
+ vec3 vR = reflect(-vV, vH);
+
+ if (isnan(pdf)) {
+ /* Seems that somethings went wrong.
+ * This only happens on extreme cases where the normal deformed too much to have any valid
+ * reflections. */
+ return;
+ }
+
+ if (data.is_planar) {
+ vec3 view_plane_normal = transform_direction(ViewMatrix, planars_data[planar_id].pl_normal);
+ /* For planar reflections, we trace inside the reflected view. */
+ vR = reflect(vR, view_plane_normal);
+ }
+
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = vR * 1e16;
+
+ RayTraceParameters params;
+ params.thickness = ssrThickness;
+ params.jitter = rand.y;
+ params.trace_quality = ssrQuality;
+ params.roughness = alpha * alpha;
+
+ vec3 hit_sP;
+ if (data.is_planar) {
+ data.is_hit = raytrace_planar(ray, params, planar_id, hit_sP);
+ }
+ else {
+ data.is_hit = raytrace(ray, params, true, hit_sP);
+ }
+ data.ray_pdf_inv = safe_rcp(pdf);
+
+ encode_hit_data(data, hit_sP, ray.origin, hitData, hitDepth);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
deleted file mode 100644
index a4b29d68ac4..00000000000
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ /dev/null
@@ -1,594 +0,0 @@
-
-#pragma BLENDER_REQUIRE(common_math_lib.glsl)
-#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
-#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
-#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
-#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
-#pragma BLENDER_REQUIRE(ssr_lib.glsl)
-
-/* Based on Stochastic Screen Space Reflections
- * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */
-
-#define MAX_MIP 9.0
-
-uniform ivec2 halfresOffset;
-
-ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar)
-{
- ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */
- hit_data.x *= (is_planar) ? -1 : 1;
- hit_data.y *= (has_hit) ? 1 : -1;
- return hit_data;
-}
-
-vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar)
-{
- is_planar = (hit_data.x < 0);
- has_hit = (hit_data.y > 0);
- vec2 hit_co = vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */
- if (is_planar) {
- hit_co.x = 1.0 - hit_co.x;
- }
- return hit_co;
-}
-
-#ifdef STEP_RAYTRACE
-
-uniform sampler2D normalBuffer;
-uniform sampler2D specroughBuffer;
-
-layout(location = 0) out ivec2 hitData;
-layout(location = 1) out float pdfData;
-
-void do_planar_ssr(
- int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 vP, float a2, vec4 rand)
-{
- float NH;
- vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
- float pdf = pdf_ggx_reflect(NH, a2);
-
- vec3 R = reflect(-V, H);
- R = reflect(R, planeNormal);
-
- /* If ray is bad (i.e. going below the plane) regenerate. */
- if (dot(R, planeNormal) > 0.0) {
- vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
- pdf = pdf_ggx_reflect(NH, a2);
-
- R = reflect(-V, H);
- R = reflect(R, planeNormal);
- }
-
- pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
-
- /* Since viewspace hit position can land behind the camera in this case,
- * we save the reflected view position (visualize it as the hit position
- * below the reflection plane). This way it's garanted that the hit will
- * be in front of the camera. That let us tag the bad rays with a negative
- * sign in the Z component. */
- vec3 hit_pos = raycast(index, vP, R * 1e16, 1e16, rand.y, ssrQuality, a2, false);
-
- hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
-}
-
-void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand)
-{
- float NH;
- /* Microfacet normal */
- vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH);
- vec3 R = reflect(-V, H);
-
- /* If ray is bad (i.e. going below the surface) regenerate. */
- /* This threshold is a bit higher than 0 to improve self intersection cases. */
- const float bad_ray_threshold = 0.085;
- if (dot(R, N) <= bad_ray_threshold) {
- H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH);
- R = reflect(-V, H);
- }
-
- if (dot(R, N) <= bad_ray_threshold) {
- H = sample_ggx(rand.xzw * vec3(1.0, 1.0, -1.0), a2, N, T, B, NH);
- R = reflect(-V, H);
- }
-
- if (dot(R, N) <= bad_ray_threshold) {
- H = sample_ggx(rand.xzw * vec3(1.0, -1.0, 1.0), a2, N, T, B, NH);
- R = reflect(-V, H);
- }
-
- if (dot(R, N) <= bad_ray_threshold) {
- /* Not worth tracing. */
- return;
- }
-
- pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */
-
- vec3 hit_pos = raycast(-1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
-
- hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
-}
-
-void main()
-{
-# ifdef FULLRES
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
- ivec2 halfres_texel = fullres_texel;
-# else
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset;
- ivec2 halfres_texel = ivec2(gl_FragCoord.xy);
-# endif
-
- float depth = texelFetch(depthBuffer, fullres_texel, 0).r;
-
- /* Default: not hits. */
- hitData = encode_hit_data(vec2(0.5), false, false);
- pdfData = 0.0;
-
- /* Early out */
- /* We can't do discard because we don't clear the render target. */
- if (depth == 1.0) {
- return;
- }
-
- vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0));
-
- /* Using view space */
- vec3 vP = get_view_space_from_depth(uvs, depth);
- vec3 P = transform_point(ViewMatrixInverse, vP);
- vec3 vV = viewCameraVec(vP);
- vec3 V = cameraVec(P);
- vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, vV);
- vec3 N = transform_direction(ViewMatrixInverse, vN);
-
- /* Retrieve pixel data */
- vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
-
- /* Early out */
- if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
- return;
- }
-
- float roughness = speccol_roughness.a;
- float roughnessSquared = max(1e-3, roughness * roughness);
- float a2 = roughnessSquared * roughnessSquared;
-
- /* Early out */
- if (roughness > ssrMaxRoughness + 0.2) {
- return;
- }
-
- vec4 rand = texelfetch_noise_tex(halfres_texel);
-
- /* Gives *perfect* reflection for very small roughness */
- if (roughness < 0.04) {
- rand.xzw *= 0.0;
- }
- /* Importance sampling bias */
- rand.x = mix(rand.x, 0.0, ssrBrdfBias);
-
- vec3 vT, vB;
- make_orthonormal_basis(vN, vT, vB); /* Generate tangent space */
-
- /* Planar Reflections */
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
- PlanarData pd = planars_data[i];
-
- float fade = probe_attenuation_planar(pd, P);
- fade *= probe_attenuation_planar_normal_roughness(pd, N, 0.0);
-
- if (fade > 0.5) {
- /* Find view vector / reflection plane intersection. */
- /* TODO optimize, use view space for all. */
- vec3 tracePosition = line_plane_intersect(P, V, pd.pl_plane_eq);
- tracePosition = transform_point(ViewMatrix, tracePosition);
- vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
-
- do_planar_ssr(i, vV, vN, vT, vB, planeNormal, tracePosition, a2, rand);
- return;
- }
- }
-
- /* Constant bias (due to depth buffer precision). Helps with self intersection. */
- /* Magic numbers for 24bits of precision.
- * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
- vP.z = get_view_z_from_depth(depth - mix(2.4e-7, 4.8e-7, depth));
-
- do_ssr(vV, vN, vT, vB, vP, a2, rand);
-}
-
-#else /* STEP_RESOLVE */
-
-uniform sampler2D prevColorBuffer; /* previous frame */
-uniform sampler2D normalBuffer;
-uniform sampler2D specroughBuffer;
-
-uniform isampler2D hitBuffer;
-uniform sampler2D pdfBuffer;
-
-uniform int neighborOffset;
-
-in vec4 uvcoordsvar;
-
-const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0),
- ivec2(1, 1),
- ivec2(-2, 0),
- ivec2(0, -2),
- ivec2(0, 0),
- ivec2(1, -1),
- ivec2(-2, 0),
- ivec2(0, 2),
- ivec2(0, 0),
- ivec2(-1, -1),
- ivec2(2, 0),
- ivec2(0, 2),
- ivec2(0, 0),
- ivec2(-1, 1),
- ivec2(2, 0),
- ivec2(0, -2),
-
- ivec2(0, 0),
- ivec2(2, 2),
- ivec2(-2, 2),
- ivec2(0, -1),
- ivec2(0, 0),
- ivec2(2, -2),
- ivec2(-2, -2),
- ivec2(0, 1),
- ivec2(0, 0),
- ivec2(-2, -2),
- ivec2(-2, 2),
- ivec2(1, 0),
- ivec2(0, 0),
- ivec2(2, 2),
- ivec2(2, -2),
- ivec2(-1, 0));
-
-out vec4 fragColor;
-
-# if 0 /* Finish reprojection with motion vectors */
-vec3 get_motion_vector(vec3 pos)
-{
-}
-
-/* http://bitsquid.blogspot.fr/2017/06/reprojecting-reflections_22.html */
-vec3 find_reflection_incident_point(vec3 cam, vec3 hit, vec3 pos, vec3 N)
-{
- float d_cam = point_plane_projection_dist(cam, pos, N);
- float d_hit = point_plane_projection_dist(hit, pos, N);
-
- if (d_hit < d_cam) {
- /* Swap */
- float tmp = d_cam;
- d_cam = d_hit;
- d_hit = tmp;
- }
-
- vec3 proj_cam = cam - (N * d_cam);
- vec3 proj_hit = hit - (N * d_hit);
-
- return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam;
-}
-# endif
-
-float brightness(vec3 c)
-{
- return max(max(c.r, c.g), c.b);
-}
-
-vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
-{
- /* TODO real reprojection with motion vectors, etc... */
- return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
-}
-
-float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
-{
- if (is_planar) {
- hit_co.x = 1.0 - hit_co.x;
- return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r;
- }
- else {
- return textureLod(depthBuffer, hit_co, 0.0).r;
- }
-}
-
-vec3 get_hit_vector(vec3 hit_pos,
- PlanarData pd,
- vec3 P,
- vec3 N,
- vec3 V,
- bool is_planar,
- inout vec2 hit_co,
- inout float mask)
-{
- vec3 hit_vec;
-
- if (is_planar) {
- /* Reflect back the hit position to have it in non-reflected world space */
- vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq);
- hit_vec = hit_pos - trace_pos;
- hit_vec = reflect(hit_vec, pd.pl_normal);
- /* Modify here so mip texel alignment is correct. */
- hit_co.x = 1.0 - hit_co.x;
- }
- else {
- /* Find hit position in previous frame. */
- hit_co = get_reprojected_reflection(hit_pos, P, N);
- hit_vec = hit_pos - P;
- }
-
- mask = screen_border_mask(hit_co);
- return hit_vec;
-}
-
-vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar)
-{
- if (is_planar) {
- return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb;
- }
- else {
- return textureLod(prevColorBuffer, ref_uvs, mip).rgb;
- }
-}
-
-vec4 get_ssr_samples(vec4 hit_pdf,
- ivec4 hit_data[2],
- PlanarData pd,
- float planar_index,
- vec3 P,
- vec3 N,
- vec3 V,
- float roughnessSquared,
- float cone_tan,
- vec2 source_uvs,
- inout float weight_acc)
-{
- bvec4 is_planar, has_hit;
- vec4 hit_co[2];
- hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x);
- hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y);
- hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z);
- hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w);
-
- vec4 hit_depth;
- hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index);
- hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index);
- hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index);
- hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index);
-
- /* Hit position in view space. */
- vec3 hit_view[4];
- hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x);
- hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y);
- hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z);
- hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w);
-
- vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z);
- homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3];
-
- /* Hit position in world space. */
- vec3 hit_pos[4];
- hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]);
- hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]);
- hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]);
- hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]);
-
- /* Get actual hit vector and hit coordinate (from last frame). */
- vec4 mask = vec4(1.0);
- hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x);
- hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y);
- hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z);
- hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w);
-
- vec4 hit_dist;
- hit_dist.x = length(hit_pos[0]);
- hit_dist.y = length(hit_pos[1]);
- hit_dist.z = length(hit_pos[2]);
- hit_dist.w = length(hit_pos[3]);
- hit_dist = max(vec4(1e-8), hit_dist);
-
- /* Normalize */
- hit_pos[0] /= hit_dist.x;
- hit_pos[1] /= hit_dist.y;
- hit_pos[2] /= hit_dist.z;
- hit_pos[3] /= hit_dist.w;
-
- /* Compute cone footprint in screen space. */
- vec4 cone_footprint = hit_dist * cone_tan;
- cone_footprint = ssrBrdfBias * 0.5 * cone_footprint *
- max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord;
-
- /* Estimate a cone footprint to sample a corresponding mipmap level. */
- vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0))));
- mip = clamp(mip, 0.0, MAX_MIP);
-
- /* Correct UVs for mipmaping mis-alignment */
- hit_co[0].xy *= mip_ratio_interp(mip.x);
- hit_co[0].zw *= mip_ratio_interp(mip.y);
- hit_co[1].xy *= mip_ratio_interp(mip.z);
- hit_co[1].zw *= mip_ratio_interp(mip.w);
-
- /* Slide 54 */
- vec4 bsdf;
- bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared);
- bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared);
- bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared);
- bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared);
-
- vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf);
-
- vec3 sample[4];
- sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x);
- sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y);
- sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z);
- sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w);
-
- /* Clamped brightness. */
- vec4 luma;
- luma.x = brightness(sample[0]);
- luma.y = brightness(sample[1]);
- luma.z = brightness(sample[2]);
- luma.w = brightness(sample[3]);
- luma = max(vec4(1e-8), luma);
- luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma;
-
- sample[0] *= luma.x;
- sample[1] *= luma.y;
- sample[2] *= luma.z;
- sample[3] *= luma.w;
-
- /* Protection against NaNs in the history buffer.
- * This could be removed if some previous pass has already
- * sanitized the input. */
- if (any(isnan(sample[0]))) {
- sample[0] = vec3(0.0);
- weight.x = 0.0;
- }
- if (any(isnan(sample[1]))) {
- sample[1] = vec3(0.0);
- weight.y = 0.0;
- }
- if (any(isnan(sample[2]))) {
- sample[2] = vec3(0.0);
- weight.z = 0.0;
- }
- if (any(isnan(sample[3]))) {
- sample[3] = vec3(0.0);
- weight.w = 0.0;
- }
-
- weight_acc += sum(weight);
-
- /* Do not add light if ray has failed. */
- vec4 accum;
- accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x);
- accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y);
- accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z);
- accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w);
- return accum;
-}
-
-void raytrace_resolve(ClosureInputGlossy cl_in,
- inout ClosureEvalGlossy cl_eval,
- inout ClosureEvalCommon cl_common,
- inout ClosureOutputGlossy cl_out)
-{
-# ifdef FULLRES
- ivec2 texel = ivec2(gl_FragCoord.xy);
-# else
- ivec2 texel = ivec2(gl_FragCoord.xy / 2.0);
-# endif
- /* Using world space */
- vec3 V = cl_common.V;
- vec3 N = cl_in.N;
- vec3 P = cl_common.P;
-
- float roughness = cl_in.roughness;
- float roughnessSquared = max(1e-3, sqr(roughness));
-
- /* Resolve SSR */
- float cone_cos = cone_cosine(roughnessSquared);
- float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
- cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */
-
- vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5;
-
- vec4 ssr_accum = vec4(0.0);
- float weight_acc = 0.0;
-
- if (roughness < ssrMaxRoughness + 0.2) {
- /* TODO optimize with textureGather */
- /* Doing these fetches early to hide latency. */
- vec4 hit_pdf;
- hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r;
- hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r;
- hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r;
- hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r;
-
- ivec4 hit_data[2];
- hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg;
- hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg;
- hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg;
- hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg;
-
- /* Find Planar Reflections affecting this pixel */
- PlanarData pd;
- float planar_index;
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
- pd = planars_data[i];
-
- float fade = probe_attenuation_planar(pd, P);
- fade *= probe_attenuation_planar_normal_roughness(pd, N, 0.0);
-
- if (fade > 0.5) {
- planar_index = float(i);
- break;
- }
- }
-
- ssr_accum += get_ssr_samples(hit_pdf,
- hit_data,
- pd,
- planar_index,
- P,
- N,
- V,
- roughnessSquared,
- cone_tan,
- source_uvs,
- weight_acc);
- }
-
- /* Compute SSR contribution */
- ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc);
- /* fade between 0.5 and 1.0 roughness */
- ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
-
- cl_eval.raytrace_radiance = ssr_accum.rgb * ssr_accum.a;
- cl_common.specular_accum -= ssr_accum.a;
-}
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy)
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- float depth = texelFetch(depthBuffer, texel, 0).r;
-
- if (depth == 1.0) {
- discard;
- }
-
- vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba;
- vec3 brdf = speccol_roughness.rgb;
- float roughness = speccol_roughness.a;
-
- if (max_v3(brdf) <= 0.0) {
- discard;
- }
-
- FragDepth = depth;
-
- viewPosition = get_view_space_from_depth(uvcoordsvar.xy, depth);
- worldPosition = transform_point(ViewMatrixInverse, viewPosition);
-
- vec2 normal_encoded = texelFetch(normalBuffer, texel, 0).rg;
- viewNormal = normal_decode(normal_encoded, viewCameraVec(viewPosition));
- worldNormal = transform_direction(ViewMatrixInverse, viewNormal);
-
- CLOSURE_VARS_DECLARE_1(Glossy);
-
- in_Glossy_0.N = worldNormal;
- in_Glossy_0.roughness = roughness;
-
- /* Do a full deferred evaluation of the glossy BSDF. The only difference is that we inject the
- * SSR resolve before the cubemap iter. BRDF term is already computed during main pass and is
- * passed as specular color. */
- CLOSURE_EVAL_FUNCTION_1(ssr_resolve, Glossy);
-
- fragColor = vec4(out_Glossy_0.radiance * brdf, 1.0);
-}
-
-#endif
diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
index 2a53a4f119f..b79cd17c567 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -26,7 +26,7 @@ void main(void)
vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */
vec2 uvs = gl_FragCoord.xy * pixel_size;
vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb;
- float sss_radius = texture(sssRadius, uvs).r;
+ float sss_radius = texture(sssRadius, uvs).r * radii_max_radius.w;
float depth = texture(depthBuffer, uvs).r;
float depth_view = get_view_z_from_depth(depth);
@@ -43,8 +43,9 @@ void main(void)
/* Compute kernel bounds in 2D. */
float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3];
vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_radius / homcoord;
- vec2 finalStep = scale * radii_max_radius.w;
- finalStep *= 0.5; /* samples range -1..1 */
+ vec2 finalStep = scale * 0.5; /* samples range -1..1 */
+
+ float sss_radius_inv = 1.0 / max(1e-8, sss_radius);
/* Center sample */
vec3 accum = sss_irradiance * kernel[0].rgb;
@@ -55,15 +56,18 @@ void main(void)
vec3 color = texture(sssIrradiance, sample_uv).rgb;
float sample_depth = texture(depthBuffer, sample_uv).r;
sample_depth = get_view_z_from_depth(sample_depth);
- /* Depth correction factor. */
- float depth_delta = depth_view - sample_depth;
- float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0);
+ /* Depth correction factor. See Real Time Realistic Skin Translucency 2010
+ * by Jimenez, eqs. 2 and 9, and D9740.
+ * Coefficient -2 follows from gaussian_profile() from gpu_material.c and
+ * from the definition of finalStep. */
+ float depth_delta = (depth_view - sample_depth) * sss_radius_inv;
+ float s = exp(-2.0 * sqr(depth_delta));
/* Out of view samples. */
if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) {
- s = 1.0;
+ s = 0.0;
}
/* Mix with first sample in failure case and apply kernel color. */
- accum += kernel[i].rgb * mix(color, sss_irradiance, s);
+ accum += kernel[i].rgb * mix(sss_irradiance, color, s);
}
#if defined(FIRST_PASS)
diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
index 28947e971d2..165aed2a46f 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
@@ -10,12 +10,6 @@ uniform mat4 prevViewProjectionMatrix;
out vec4 FragColor;
-vec4 safe_color(vec4 c)
-{
- /* Clamp to avoid black square artifacts if a pixel goes NaN. */
- return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
-}
-
#ifdef USE_REPROJECTION
/**
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
index 0d0ae6ea4a5..9ecc50d9df5 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -1,4 +1,5 @@
+#pragma BLENDER_REQUIRE(random_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
#pragma BLENDER_REQUIRE(irradiance_lib.glsl)
@@ -10,7 +11,6 @@ uniform float lodMax;
uniform float intensityFac;
uniform float sampleCount;
-uniform float invSampleCount;
in vec3 worldPosition;
@@ -147,14 +147,16 @@ void main()
float weight = 0.0;
vec3 out_radiance = vec3(0.0);
for (float i = 0; i < sampleCount; i++) {
- vec3 L = sample_hemisphere(i, invSampleCount, N, T, B); /* Microfacet normal */
+ vec3 Xi = rand2d_to_cylinder(hammersley_2d(i, sampleCount));
+
+ float pdf;
+ vec3 L = sample_uniform_hemisphere(Xi, N, T, B, pdf);
float NL = dot(N, L);
if (NL > 0.0) {
/* Coarse Approximation of the mapping distortion
* Unit Sphere -> Cubemap Face */
const float dist = 4.0 * M_PI / 6.0;
- float pdf = pdf_hemisphere();
/* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */
float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax);
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
index 35fdbcb715f..a5d11f52a1d 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
@@ -1,9 +1,10 @@
+#pragma BLENDER_REQUIRE(random_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
uniform samplerCube probeHdr;
-uniform float roughnessSquared;
+uniform float roughness;
uniform float texelSize;
uniform float lodFactor;
uniform float lodMax;
@@ -12,17 +13,11 @@ uniform float intensityFac;
uniform float fireflyFactor;
uniform float sampleCount;
-uniform float invSampleCount;
in vec3 worldPosition;
out vec4 FragColor;
-float brightness(vec3 c)
-{
- return max(max(c.r, c.g), c.b);
-}
-
vec3 octahedral_to_cubemap_proj(vec2 co)
{
co = co * 2.0 - 1.0;
@@ -52,7 +47,11 @@ void main()
float weight = 0.0;
vec3 out_radiance = vec3(0.0);
for (float i = 0; i < sampleCount; i++) {
- vec3 H = sample_ggx(i, invSampleCount, roughnessSquared, N, T, B); /* Microfacet normal */
+ vec3 Xi = rand2d_to_cylinder(hammersley_2d(i, sampleCount));
+
+ float pdf;
+ /* Microfacet normal */
+ vec3 H = sample_ggx(Xi, roughness, V, N, T, B, pdf);
vec3 L = -reflect(V, H);
float NL = dot(N, L);
@@ -62,14 +61,13 @@ void main()
/* Coarse Approximation of the mapping distortion
* Unit Sphere -> Cubemap Face */
const float dist = 4.0 * M_PI / 6.0;
- float pdf = pdf_ggx_reflect(NH, roughnessSquared);
/* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */
float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax);
vec3 l_col = textureLod(probeHdr, L, lod).rgb;
/* Clamped brightness. */
- float luma = max(1e-8, brightness(l_col));
+ float luma = max(1e-8, max_v3(l_col));
l_col *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
out_radiance += l_col * NL;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
index b802b39c56e..d25ef23a706 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
@@ -1,4 +1,5 @@
+#pragma BLENDER_REQUIRE(random_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(irradiance_lib.glsl)
@@ -14,7 +15,7 @@ uniform float visibilityRange;
uniform float visibilityBlur;
uniform float sampleCount;
-uniform float invSampleCount;
+uniform float;
out vec4 FragColor;
@@ -80,13 +81,15 @@ void main()
vec2 accum = vec2(0.0);
for (float i = 0; i < sampleCount; i++) {
- vec3 samp = sample_cone(i, invSampleCount, M_PI_2 * visibilityBlur, cos, T, B);
+ vec3 Xi = rand2d_to_cylinder(hammersley_2d(i, sampleCount));
+
+ vec3 samp = sample_uniform_cone(Xi, M_PI_2 * visibilityBlur, cos, T, B);
float depth = texture(probeDepth, samp).r;
depth = get_world_distance(depth, samp);
accum += vec2(depth, depth * depth);
}
- accum *= invSampleCount;
+ accum /= sampleCount;
accum = abs(accum);
/* Encode to normalized RGBA 8 */
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index de384146b80..c9b5d0dea36 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -304,5 +304,8 @@ vec3 probe_evaluate_grid(GridData gd, vec3 P, vec3 N, vec3 localpos)
vec3 probe_evaluate_world_diff(vec3 N)
{
+ if (prbNumRenderGrid == 0) {
+ return vec3(0);
+ }
return irradiance_from_cell_get(0, N);
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
index 0f575dfc2ed..cf44a04b707 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
@@ -2,6 +2,8 @@
* Simple down-sample shader. Takes the average of the 4 texels of lower mip.
*/
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform sampler2DArray source;
uniform float fireflyFactor;
@@ -10,11 +12,6 @@ flat in float layer;
out vec4 FragColor;
-float brightness(vec3 c)
-{
- return max(max(c.r, c.g), c.b);
-}
-
void main()
{
#if 0
@@ -34,7 +31,7 @@ void main()
FragColor *= 0.25;
/* Clamped brightness. */
- float luma = max(1e-8, brightness(FragColor.rgb));
+ float luma = max(1e-8, max_v3(FragColor.rgb));
FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index 04ad53eabb7..5d3db8d4966 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -268,39 +268,37 @@ float light_shadowing(LightData ld, vec3 P, float vis)
}
#ifndef VOLUMETRICS
-float light_contact_shadows(
- LightData ld, vec3 P, vec3 vP, float tracing_depth, vec3 vNg, float rand_x, float vis)
+float light_contact_shadows(LightData ld, vec3 P, vec3 vP, vec3 vNg, float rand_x, float vis)
{
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
ShadowData sd = shadows_data[int(ld.l_shadowid)];
/* Only compute if not already in shadow. */
if (sd.sh_contact_dist > 0.0) {
/* Contact Shadows. */
- vec3 ray_ori, ray_dir;
- float trace_distance;
+ Ray ray;
if (ld.l_type == SUN) {
- trace_distance = sd.sh_contact_dist;
- ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
+ ray.direction = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec *
+ sd.sh_contact_dist;
}
else {
- ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
- float len = length(ray_dir);
- trace_distance = min(sd.sh_contact_dist, len);
- ray_dir *= trace_distance / len;
+ ray.direction = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
+ ray.direction *= saturate(sd.sh_contact_dist * safe_rcp(length(ray.direction)));
}
- ray_dir = transform_direction(ViewMatrix, ray_dir);
- ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset;
+ ray.direction = transform_direction(ViewMatrix, ray.direction);
+ ray.origin = vP + vNg * sd.sh_contact_offset;
- vec3 hit_pos = raycast(
- -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
+ RayTraceParameters params;
+ params.thickness = sd.sh_contact_thickness;
+ params.jitter = rand_x;
+ params.trace_quality = 0.1;
+ params.roughness = 0.001;
- if (hit_pos.z > 0.0) {
- hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
- float hit_dist = distance(vP, hit_pos);
- float dist_ratio = hit_dist / trace_distance;
- return saturate(dist_ratio * 3.0 - 2.0);
+ vec3 hit_position_unused;
+
+ if (raytrace(ray, params, false, hit_position_unused)) {
+ return 0.0;
}
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/random_lib.glsl b/source/blender/draw/engines/eevee/shaders/random_lib.glsl
new file mode 100644
index 00000000000..25a3e0f56b4
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/random_lib.glsl
@@ -0,0 +1,38 @@
+
+/**
+ * Random numbers and low discrepency sequences utilities.
+ **/
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
+/* From: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
+float van_der_corput_radical_inverse(uint bits)
+{
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ /* Same as dividing by 0x100000000. */
+ return float(bits) * 2.3283064365386963e-10;
+}
+
+vec2 hammersley_2d(float i, float sample_count)
+{
+ vec2 rand;
+ rand.x = i / sample_count;
+ rand.y = van_der_corput_radical_inverse(uint(i));
+ return rand;
+}
+
+/* This transform a 2d random sample (in [0..1] range) to a sample located on a cylinder of the
+ * same range. This is because the sampling functions expect such a random sample which is
+ * normally precomputed. */
+vec3 rand2d_to_cylinder(vec2 rand)
+{
+ float theta = rand.x;
+ float phi = (rand.y - 0.5) * M_2PI;
+ float cos_phi = cos(phi);
+ float sin_phi = sqrt(1.0 - sqr(cos_phi)) * sign(phi);
+ return vec3(theta, cos_phi, sin_phi);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index aebd1c3aef3..5c4fe6d47a0 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -3,261 +3,214 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+/**
+ * Screen-Space Raytracing functions.
+ */
+
uniform sampler2D maxzBuffer;
uniform sampler2DArray planarDepth;
-#define MAX_STEP 256
+struct Ray {
+ vec3 origin;
+ /* Ray direction premultiplied by its maximum length. */
+ vec3 direction;
+};
-float sample_depth(vec2 uv, int index, float lod)
+/* Inputs expected to be in viewspace. */
+void raytrace_clip_ray_to_near_plane(inout Ray ray)
{
-#ifdef PLANAR_PROBE_RAYTRACE
- if (index > -1) {
- return textureLod(planarDepth, vec3(uv, index), 0.0).r;
- }
- else {
-#endif
- lod = clamp(floor(lod), 0.0, 8.0);
- /* Correct UVs for mipmaping mis-alignment */
- uv *= mipRatio[int(lod) + hizMipOffset];
- return textureLod(maxzBuffer, uv, lod).r;
-#ifdef PLANAR_PROBE_RAYTRACE
+ float near_dist = get_view_z_from_depth(0.0);
+ if ((ray.origin.z + ray.direction.z) > near_dist) {
+ ray.direction *= abs((near_dist - ray.origin.z) / ray.direction.z);
}
-#endif
}
-vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod)
+/* Screenspace ray ([0..1] "uv" range) where direction is normalize to be as small as one
+ * full-resolution pixel. The ray is also clipped to all frustum sides.
+ */
+struct ScreenSpaceRay {
+ vec4 origin;
+ vec4 direction;
+ float max_time;
+};
+
+void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray)
{
- vec4 depths;
-#ifdef PLANAR_PROBE_RAYTRACE
- if (index > -1) {
- depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r;
- depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r;
- depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r;
- depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r;
- }
- else {
-#endif
- depths.x = textureLod(maxzBuffer, uv1.xy, lod).r;
- depths.y = textureLod(maxzBuffer, uv1.zw, lod).r;
- depths.z = textureLod(maxzBuffer, uv2.xy, lod).r;
- depths.w = textureLod(maxzBuffer, uv2.zw, lod).r;
-#ifdef PLANAR_PROBE_RAYTRACE
+ /* Constant bias (due to depth buffer precision). Helps with self intersection. */
+ /* Magic numbers for 24bits of precision.
+ * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
+ const float bias = -2.4e-7 * 2.0;
+ ray.origin.zw += bias;
+ ray.direction.zw += bias;
+
+ ray.direction -= ray.origin;
+ /* If the line is degenerate, make it cover at least one pixel
+ * to not have to handle zero-pixel extent as a special case later */
+ if (len_squared(ray.direction.xy) < 0.00001) {
+ ray.direction.xy = vec2(0.0, 0.00001);
}
-#endif
- return depths;
+ float ray_len_sqr = len_squared(ray.direction.xyz);
+ /* Make ray.direction cover one pixel. */
+ bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y);
+ ray.direction /= (is_more_vertical) ? abs(ray.direction.y) : abs(ray.direction.x);
+ ray.direction *= (is_more_vertical) ? ssrPixelSize.y : ssrPixelSize.x;
+ /* Clip to segment's end. */
+ ray.max_time = sqrt(ray_len_sqr * safe_rcp(len_squared(ray.direction.xyz)));
+ /* Clipping to frustum sides. */
+ float clip_dist = line_unit_box_intersect_dist_safe(ray.origin.xyz, ray.direction.xyz);
+ ray.max_time = min(ray.max_time, clip_dist);
+ /* Convert to texture coords [0..1] range. */
+ ray.origin = ray.origin * 0.5 + 0.5;
+ ray.direction *= 0.5;
}
-float refine_isect(float prev_delta, float curr_delta)
+ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray)
{
- /**
- * Simplification of 2D intersection :
- * r0 = (0.0, prev_ss_ray.z);
- * r1 = (1.0, curr_ss_ray.z);
- * d0 = (0.0, prev_hit_depth_sample);
- * d1 = (1.0, curr_hit_depth_sample);
- * vec2 r = r1 - r0;
- * vec2 d = d1 - d0;
- * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d);
- *
- * We only want isect.x to know how much stride we need. So it simplifies :
- *
- * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d);
- * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d);
- */
- return saturate(prev_delta / (prev_delta - curr_delta));
+ ScreenSpaceRay ssray;
+ ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin);
+ ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction);
+
+ raytrace_screenspace_ray_finalize(ssray);
+ return ssray;
}
-void prepare_raycast(vec3 ray_origin,
- vec3 ray_dir,
- float thickness,
- int index,
- out vec4 ss_step,
- out vec4 ss_ray,
- out float max_time)
+ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray, float thickness)
{
- /* Negate the ray direction if it goes towards the camera.
- * This way we don't need to care if the projected point
- * is behind the near plane. */
- float z_sign = -sign(ray_dir.z);
- vec3 ray_end = ray_origin + z_sign * ray_dir;
-
- /* Project into screen space. */
- vec4 ss_start, ss_end;
- ss_start.xyz = project_point(ProjectionMatrix, ray_origin);
- ss_end.xyz = project_point(ProjectionMatrix, ray_end);
-
- /* We interpolate the ray Z + thickness values to check if depth is within threshold. */
- ray_origin.z -= thickness;
- ray_end.z -= thickness;
- ss_start.w = project_point(ProjectionMatrix, ray_origin).z;
- ss_end.w = project_point(ProjectionMatrix, ray_end).z;
-
- /* XXX This is a hack. A better method is welcome! */
- /* We take the delta between the offsetted depth and the depth and subtract it from the ray
- * depth. This will change the world space thickness appearance a bit but we can have negative
- * values without worries. We cannot do this in viewspace because of the perspective division. */
- ss_start.w = 2.0 * ss_start.z - ss_start.w;
- ss_end.w = 2.0 * ss_end.z - ss_end.w;
-
- ss_step = ss_end - ss_start;
- max_time = length(ss_step.xyz);
- ss_step = z_sign * ss_step / length(ss_step.xyz);
+ ScreenSpaceRay ssray;
+ ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin);
+ ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction);
+ /* Interpolate thickness in screen space.
+ * Calculate thickness further away to avoid near plane clipping issues. */
+ ssray.origin.w = get_depth_from_view_z(ray.origin.z - thickness) * 2.0 - 1.0;
+ ssray.direction.w = get_depth_from_view_z(ray.origin.z + ray.direction.z - thickness) * 2.0 -
+ 1.0;
+
+ raytrace_screenspace_ray_finalize(ssray);
+ return ssray;
+}
- /* If the line is degenerate, make it cover at least one pixel
- * to not have to handle zero-pixel extent as a special case later */
- if (dot(ss_step.xy, ss_step.xy) < 0.00001) {
- ss_step.xy = vec2(0.0, 0.0001);
+struct RayTraceParameters {
+ /** ViewSpace thickness the objects */
+ float thickness;
+ /** Jitter along the ray to avoid banding artifact when steps are too large. */
+ float jitter;
+ /** Determine how fast the sample steps are getting bigger. */
+ float trace_quality;
+ /** Determine how we can use lower depth mipmaps to make the tracing faster. */
+ float roughness;
+};
+
+/* Returns true on hit. */
+/* TODO fclem remove the backface check and do it the SSR resolve code. */
+bool raytrace(Ray ray,
+ RayTraceParameters params,
+ const bool discard_backface,
+ out vec3 hit_position)
+{
+ /* Clip to near plane for perspective view where there is a singularity at the camera origin. */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ raytrace_clip_ray_to_near_plane(ray);
}
- /* Make ss_step cover one pixel. */
- ss_step /= max(abs(ss_step.x), abs(ss_step.y));
- ss_step *= (abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y;
-
- /* Clip to segment's end. */
- max_time /= length(ss_step.xyz);
- /* Clipping to frustum sides. */
- max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz));
+ ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray, params.thickness);
/* Avoid no iteration. */
- max_time = max(max_time, 1.0);
+ if (ssray.max_time < 1.1) {
+ hit_position = ssray.origin.xyz + ssray.direction.xyz;
+ return false;
+ }
- /* Convert to texture coords. Z component included
- * since this is how it's stored in the depth buffer.
- * 4th component how far we are on the ray */
-#ifdef PLANAR_PROBE_RAYTRACE
- /* Planar Reflections have X mirrored. */
- vec2 m = (index > -1) ? vec2(-0.5, 0.5) : vec2(0.5);
-#else
- const vec2 m = vec2(0.5);
-#endif
- ss_ray = ss_start * m.xyyy + 0.5;
- ss_step *= m.xyyy;
-
- /* take the center of the texel. */
- // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset);
-}
+ float prev_delta = 0.0, prev_time = 0.0;
+ float depth_sample = get_depth_from_view_z(ray.origin.z);
+ float delta = depth_sample - ssray.origin.z;
-/* See times_and_deltas. */
-#define curr_time times_and_deltas.x
-#define prev_time times_and_deltas.y
-#define curr_delta times_and_deltas.z
-#define prev_delta times_and_deltas.w
-
-// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */
-/* Return the hit position, and negate the z component (making it positive) if not hit occurred. */
-/* __ray_dir__ is the ray direction premultiplied by its maximum length */
-vec3 raycast(int index,
- vec3 ray_origin,
- vec3 ray_dir,
- float thickness,
- float ray_jitter,
- float trace_quality,
- float roughness,
- const bool discard_backface)
-{
- vec4 ss_step, ss_start;
- float max_time;
- prepare_raycast(ray_origin, ray_dir, thickness, index, ss_step, ss_start, max_time);
+ float lod_fac = saturate(fast_sqrt(params.roughness) * 2.0 - 0.4);
- float max_trace_time = max(0.01, max_time - 0.01);
+ /* Cross at least one pixel. */
+ float t = 1.001, time = 1.001;
+ bool hit = false;
+ const float max_steps = 255.0;
+ for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) {
+ float stride = 1.0 + iter * params.trace_quality;
+ float lod = log2(stride) * lod_fac;
-#ifdef GROUPED_FETCHES
- ray_jitter *= 0.25;
-#endif
+ prev_time = time;
+ prev_delta = delta;
- /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */
- vec4 times_and_deltas = vec4(0.0);
+ time = min(t + stride * params.jitter, ssray.max_time);
+ t += stride;
- float ray_time = 0.0;
- float depth_sample = sample_depth(ss_start.xy, index, 0.0);
- curr_delta = depth_sample - ss_start.z;
+ vec4 ss_p = ssray.origin + ssray.direction * time;
+ depth_sample = textureLod(maxzBuffer, ss_p.xy * hizUvScale.xy, floor(lod)).r;
- float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4);
- bool hit = false;
- float iter;
- for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) {
- /* Minimum stride of 2 because we are using half res minmax zbuffer. */
- /* WORKAROUND: Factor is a bit higher than 2 to avoid some banding. To investigate. */
- float stride = max(1.0, iter * trace_quality) * (2.0 + 0.05);
- float lod = log2(stride * 0.5 * trace_quality) * lod_fac;
- ray_time += stride;
-
- /* Save previous values. */
- times_and_deltas.xyzw = times_and_deltas.yxwz;
-
-#ifdef GROUPED_FETCHES
- stride *= 4.0;
- vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter);
-
- vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time));
-
- vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy;
- vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww;
-
- vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod);
-
- vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw;
- vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz);
-
- vec4 deltas = depth_samples - ray_z;
- /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */
- bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0));
- hit = any(test);
-
- if (hit) {
- vec2 m = vec2(1.0, 0.0); /* Mask */
-
- vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx;
- ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx :
- ret_times_and_deltas;
- ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx :
- ret_times_and_deltas;
- times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy +
- times_and_deltas.yyww * m.yxyx :
- ret_times_and_deltas;
-
- depth_sample = depth_samples.w;
- depth_sample = (test.z) ? depth_samples.z : depth_sample;
- depth_sample = (test.y) ? depth_samples.y : depth_sample;
- depth_sample = (test.x) ? depth_samples.x : depth_sample;
- }
- else {
- curr_time = times.w;
- curr_delta = deltas.w;
- }
-#else
- float jit_stride = mix(2.0, stride, ray_jitter);
-
- curr_time = min(ray_time + jit_stride, max_trace_time);
- vec4 ss_ray = ss_start + ss_step * curr_time;
-
- depth_sample = sample_depth(ss_ray.xy, index, lod);
-
- float prev_w = ss_start.w + ss_step.w * prev_time;
- curr_delta = depth_sample - ss_ray.z;
- hit = (curr_delta <= 0.0) && (prev_w <= depth_sample);
-#endif
+ delta = depth_sample - ss_p.z;
+ /* Check if the ray is below the surface ... */
+ hit = (delta < 0.0);
+ /* ... and above it with the added thickness. */
+ hit = hit && (delta > ss_p.z - ss_p.w || abs(delta) < abs(ssray.direction.z * stride * 2.0));
}
+ /* Discard backface hits. */
+ hit = hit && !(discard_backface && prev_delta < 0.0);
+ /* Reject hit if background. */
+ hit = hit && (depth_sample != 1.0);
+ /* Refine hit using intersection between the sampled heightfield and the ray.
+ * This simplifies nicely to this single line. */
+ time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta)));
+
+ hit_position = ssray.origin.xyz + ssray.direction.xyz * time;
- /* Discard backface hits. Only do this if the ray traveled enough to avoid losing intricate
- * contact reflections. This is only used for SSReflections. */
- if (discard_backface && prev_delta < 0.0 && curr_time > 4.1) {
- hit = false;
+ return hit;
+}
+
+bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out vec3 hit_position)
+{
+ /* Clip to near plane for perspective view where there is a singularity at the camera origin. */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ raytrace_clip_ray_to_near_plane(ray);
}
- /* Reject hit if background. */
- hit = hit && (depth_sample != 1.0);
+ ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray);
+
+ /* Planar Reflections have X mirrored. */
+ ssray.origin.x = 1.0 - ssray.origin.x;
+ ssray.direction.x = -ssray.direction.x;
+
+ float prev_delta = 0.0, prev_time = 0.0;
+ float depth_sample = texture(planarDepth, vec3(ssray.origin.xy, planar_ref_id)).r;
+ float delta = depth_sample - ssray.origin.z;
+
+ float t = 0.0, time = 0.0;
+ /* On very sharp reflections, the ray can be perfectly aligned with the view direction
+ * making the tracing useless. Bypass tracing in this case. */
+ bool hit = false;
+ const float max_steps = 255.0;
+ for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) {
+ float stride = 1.0 + iter * params.trace_quality;
+
+ prev_time = time;
+ prev_delta = delta;
+
+ time = min(t + stride * params.jitter, ssray.max_time);
+ t += stride;
- curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time;
- ray_time = (hit) ? curr_time : ray_time;
+ vec4 ss_ray = ssray.origin + ssray.direction * time;
- /* Clip to frustum. */
- ray_time = max(0.001, min(ray_time, max_time - 1.5));
+ depth_sample = texture(planarDepth, vec3(ss_ray.xy, planar_ref_id)).r;
- vec4 ss_ray = ss_start + ss_step * ray_time;
+ delta = depth_sample - ss_ray.z;
+ /* Check if the ray is below the surface. */
+ hit = (delta < 0.0);
+ }
+ /* Reject hit if background. */
+ hit = hit && (depth_sample != 1.0);
+ /* Refine hit using intersection between the sampled heightfield and the ray.
+ * This simplifies nicely to this single line. */
+ time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta)));
+
+ hit_position = ssray.origin.xyz + ssray.direction.xyz * time;
+ /* Planar Reflections have X mirrored. */
+ hit_position.x = 1.0 - hit_position.x;
- /* Tag Z if ray failed. */
- ss_ray.z *= (hit) ? 1.0 : -1.0;
- return ss_ray.xyz;
+ return hit;
}
float screen_border_mask(vec2 hit_co)
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
index c48828b7b8d..ad0d682dcf4 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
@@ -28,13 +28,6 @@ void main()
vec4 rand = texelfetch_noise_tex(texel);
float accum_light = 0.0;
- float tracing_depth = depth;
- /* Constant bias (due to depth buffer precision) */
- /* Magic numbers for 24bits of precision.
- * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
- tracing_depth -= mix(2.4e-7, 4.8e-7, depth);
- /* Convert to view Z. */
- tracing_depth = get_view_z_from_depth(tracing_depth);
vec3 vP = get_view_space_from_depth(uvs, depth);
vec3 P = transform_point(ViewMatrixInverse, vP);
@@ -50,7 +43,7 @@ void main()
float l_vis = light_shadowing(ld, P, 1.0);
- l_vis *= light_contact_shadows(ld, P, vP, tracing_depth, vNg, rand.x, 1.0);
+ l_vis *= light_contact_shadows(ld, P, vP, vNg, rand.x, 1.0);
accum_light += l_vis;
}
diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
index 15c28efe622..612e95832e4 100644
--- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
@@ -9,23 +9,26 @@
#define BTDF_BIAS 0.85
+uniform sampler2D refractColorBuffer;
+
+uniform float refractionDepth;
+
vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand)
{
- float a2 = max(5e-6, roughnessSquared * roughnessSquared);
+ float alpha = max(0.002, roughnessSquared);
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, BTDF_BIAS);
vec3 T, B;
- float NH;
make_orthonormal_basis(N, T, B);
- vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
- float pdf = pdf_ggx_reflect(NH, a2);
+ float pdf;
+ /* Microfacet normal */
+ vec3 H = sample_ggx(rand.xzw, alpha, V, N, T, B, pdf);
/* If ray is bad (i.e. going below the plane) regenerate. */
if (F_eta(ior, dot(H, V)) < 1.0) {
- H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
- pdf = pdf_ggx_reflect(NH, a2);
+ H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), alpha, V, N, T, B, pdf);
}
vec3 vV = viewCameraVec(vP);
@@ -39,10 +42,20 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness
R = transform_direction(ViewMatrix, R);
- vec3 hit_pos = raycast(
- -1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false);
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = R * 1e16;
+
+ RayTraceParameters params;
+ params.thickness = ssrThickness;
+ params.jitter = rand.y;
+ params.trace_quality = ssrQuality;
+ params.roughness = roughnessSquared;
- if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) {
+ vec3 hit_pos;
+ bool hit = raytrace(ray, params, false, hit_pos);
+
+ if (hit && (F_eta(ior, dot(H, V)) < 1.0)) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(hit_pos, vP);
@@ -65,13 +78,10 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness
vec2 hit_uvs = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5;
/* Texel footprint */
- vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy);
+ vec2 texture_size = vec2(textureSize(refractColorBuffer, 0).xy) / hizUvScale.xy;
float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0);
- /* Correct UVs for mipmaping mis-alignment */
- hit_uvs *= mip_ratio_interp(mip);
-
- vec3 spec = textureLod(colorBuffer, hit_uvs, mip).xyz;
+ vec3 spec = textureLod(refractColorBuffer, hit_uvs * hizUvScale.xy, mip).xyz;
float mask = screen_border_mask(hit_uvs);
return vec4(spec, mask);
diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
index 62930b9944a..889bf439d5f 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
@@ -79,7 +79,7 @@ void main()
#endif
#ifndef USE_ALPHA_BLEND
- float alpha_div = 1.0 / max(1e-8, alpha);
+ float alpha_div = safe_rcp(alpha);
outRadiance.rgb *= alpha_div;
ssrData.rgb *= alpha_div;
# ifdef USE_SSS
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index e80dc1761f0..0acb35b2399 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -1,12 +1,5 @@
/** This describe the entire interface of the shader. */
-/* Samplers */
-uniform sampler2D colorBuffer;
-uniform sampler2D depthBuffer;
-
-/* Uniforms */
-uniform float refractionDepth;
-
#define SURFACE_INTERFACE \
vec3 worldPosition; \
vec3 viewPosition; \
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
index aedc8668387..bb905f8694b 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
@@ -168,7 +168,7 @@ void main()
vec3 rev = texture(revealBuf, uv).rgb;
if (threshold.x > -1.0) {
if (threshold.y > -1.0) {
- if (all(lessThan(abs(col - threshold), vec3(0.05)))) {
+ if (any(greaterThan(abs(col - threshold), vec3(0.05)))) {
weight = 0.0;
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index fe0741d1606..9c58a2b574f 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -28,6 +28,7 @@
#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_mask.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "DNA_brush_types.h"
@@ -417,6 +418,10 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
+ if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
+ return;
+ }
+
OVERLAY_StorageList *stl = vedata->stl;
OVERLAY_PrivateData *pd = stl->pd;
GPUBatch *geom;
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index fcd626eb92b..f902a95a19a 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -935,8 +935,15 @@ GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
int DRW_cache_object_material_count_get(struct Object *ob)
{
+ short type = ob->type;
+
Mesh *me = BKE_object_get_evaluated_mesh(ob);
- short type = (me != NULL) ? OB_MESH : ob->type;
+ if (me != NULL && type != OB_POINTCLOUD) {
+ /* Some object types (e.g. curves) can have a Curve in ob->data, but will be rendered as mesh.
+ * For point clouds this never happens. Ideally this check would happen at another level and we
+ * would just have to care about ob->data here. */
+ type = OB_MESH;
+ }
switch (type) {
case OB_MESH:
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index f540ff09032..84bc0327aa2 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -46,10 +46,10 @@
struct DupliObject;
struct Object;
-/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
+/** Use draw manager to call GPU_select, see: #DRW_draw_select_loop */
#define USE_GPU_SELECT
-/* Use drawcall batching using instanced rendering. */
+/** Use draw-call batching using instanced rendering. */
#define USE_BATCHING 1
// #define DRW_DEBUG_CULLING
diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index b5151293c1b..d7438b7e0f0 100644
--- a/source/blender/draw/intern/draw_select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.h"
#include "BLI_bitmap.h"
#include "BLI_bitmap_draw_2d.h"
#include "BLI_rect.h"
@@ -336,6 +337,26 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
return ret;
}
+struct SelectReadData {
+ const void *val_ptr;
+ uint id_min;
+ uint id_max;
+ uint r_index;
+};
+
+static bool select_buffer_test_fn(const void *__restrict value, void *__restrict userdata)
+{
+ struct SelectReadData *data = userdata;
+ uint hit_id = *(uint *)value;
+ if (hit_id && hit_id >= data->id_min && hit_id < data->id_max) {
+ /* Start at 1 to confirm. */
+ data->val_ptr = value;
+ data->r_index = (hit_id - data->id_min) + 1;
+ return true;
+ }
+ return false;
+}
+
/**
* Find the selection id closest to \a center.
* \param dist: Use to initialize the distance,
@@ -349,13 +370,8 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
const uint id_max,
uint *dist)
{
- /* Smart function to sample a rect spiraling outside, nice for selection ID. */
-
/* Create region around center (typically the mouse cursor).
- * This must be square and have an odd width,
- * the spiraling algorithm does not work with arbitrary rectangles. */
-
- uint index = 0;
+ * This must be square and have an odd width. */
rcti rect;
BLI_rcti_init_pt_radius(&rect, center, *dist);
@@ -364,7 +380,6 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
int width = BLI_rcti_size_x(&rect);
int height = width;
- BLI_assert(width == height);
/* Read from selection framebuffer. */
@@ -372,64 +387,23 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
const uint *buf = DRW_select_buffer_read(depsgraph, region, v3d, &rect, &buf_len);
if (buf == NULL) {
- return index;
+ return 0;
}
- BLI_assert(width * height == buf_len);
-
- /* Spiral, starting from center of buffer. */
- int spiral_offset = height * (int)(width / 2) + (height / 2);
- int spiral_direction = 0;
-
- for (int nr = 1; nr <= height; nr++) {
- for (int a = 0; a < 2; a++) {
- for (int b = 0; b < nr; b++) {
- /* Find hit within the specified range. */
- uint hit_id = buf[spiral_offset];
-
- if (hit_id && hit_id >= id_min && hit_id < id_max) {
- /* Get x/y from spiral offset. */
- int hit_x = spiral_offset % width;
- int hit_y = spiral_offset / width;
-
- int center_x = width / 2;
- int center_y = height / 2;
+ const int shape[2] = {height, width};
+ const int center_yx[2] = {(height - 1) / 2, (width - 1) / 2};
+ struct SelectReadData data = {NULL, id_min, id_max, 0};
+ BLI_array_iter_spiral_square(buf, shape, center_yx, select_buffer_test_fn, &data);
- /* Manhattan distance in keeping with other screen-based selection. */
- *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y));
-
- /* Indices start at 1 here. */
- index = (hit_id - id_min) + 1;
- goto exit;
- }
-
- /* Next spiral step. */
- if (spiral_direction == 0) {
- spiral_offset += 1; /* right */
- }
- else if (spiral_direction == 1) {
- spiral_offset -= width; /* down */
- }
- else if (spiral_direction == 2) {
- spiral_offset -= 1; /* left */
- }
- else {
- spiral_offset += width; /* up */
- }
-
- /* Stop if we are outside the buffer. */
- if (spiral_offset < 0 || spiral_offset >= buf_len) {
- goto exit;
- }
- }
-
- spiral_direction = (spiral_direction + 1) % 4;
- }
+ if (data.val_ptr) {
+ size_t offset = ((size_t)data.val_ptr - (size_t)buf) / sizeof(*buf);
+ int hit_x = offset % width;
+ int hit_y = offset / width;
+ *dist = (uint)(abs(hit_y - center_yx[0]) + abs(hit_x - center_yx[1]));
}
-exit:
MEM_freeN((void *)buf);
- return index;
+ return data.r_index;
}
/** \} */
diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
index 643d7e7d942..7b701d1d81b 100644
--- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
@@ -83,6 +83,13 @@ float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
return min_v3(furthestplane);
}
+float line_unit_box_intersect_dist_safe(vec3 lineorigin, vec3 linedirection)
+{
+ vec3 safe_linedirection = max(vec3(1e-8), abs(linedirection)) *
+ mix(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0)));
+ return line_unit_box_intersect_dist(lineorigin, safe_linedirection);
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -116,4 +123,14 @@ vec3 normal_decode(vec2 enc, vec3 view)
return n;
}
+vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
+{
+ return T * vector.x + B * vector.y + N * vector.z;
+}
+
+vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B)
+{
+ return vec3(dot(T, vector), dot(B, vector), dot(N, vector));
+}
+
/** \} */
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index d02fd27f35f..0344b977139 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -128,6 +128,12 @@ vec3 normalize_len(vec3 v, out float len)
return v / len;
}
+vec4 safe_color(vec4 c)
+{
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index 8ab626ed7ba..96d544fd855 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -288,7 +288,6 @@ TEST_F(DrawTest, overlay_glsl_shaders)
TEST_F(DrawTest, eevee_glsl_shaders_static)
{
- EEVEE_shaders_lightprobe_shaders_init();
EEVEE_shaders_material_shaders_init();
EXPECT_NE(EEVEE_shaders_bloom_blit_get(false), nullptr);
@@ -340,7 +339,6 @@ TEST_F(DrawTest, eevee_glsl_shaders_static)
EXPECT_NE(EEVEE_shaders_effect_motion_blur_velocity_tiles_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_motion_blur_velocity_tiles_expand_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_sh_get(), nullptr);
- EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_ggx_lut_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_ggx_refraction_lut_sh_get(), nullptr);
@@ -373,10 +371,8 @@ TEST_F(DrawTest, eevee_glsl_shaders_static)
EXPECT_NE(EEVEE_shaders_velocity_resolve_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_taa_resolve_sh_get(EFFECT_TAA), nullptr);
EXPECT_NE(EEVEE_shaders_taa_resolve_sh_get(EFFECT_TAA_REPROJECT), nullptr);
- for (int index = 0; index < SSR_MAX_SHADER; index++) {
- EEVEE_SSRShaderOptions ssr_option = (EEVEE_SSRShaderOptions)index;
- EXPECT_NE(EEVEE_shaders_effect_screen_raytrace_sh_get(ssr_option), nullptr);
- }
+ EXPECT_NE(EEVEE_shaders_effect_reflection_trace_sh_get(), nullptr);
+ EXPECT_NE(EEVEE_shaders_effect_reflection_resolve_sh_get(), nullptr);
EEVEE_shaders_free();
}
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index a2ae350ce4b..092198cea86 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -53,6 +53,7 @@ if(WITH_BLENDER)
add_subdirectory(space_outliner)
add_subdirectory(space_script)
add_subdirectory(space_sequencer)
+ add_subdirectory(space_spreadsheet)
add_subdirectory(space_statusbar)
add_subdirectory(space_text)
add_subdirectory(space_topbar)
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 38820e05869..711ec0a9d22 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2544,7 +2544,7 @@ static bool animchannels_find_poll(bContext *C)
}
/* find_invoke() - Get initial channels */
-static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
@@ -2557,7 +2557,7 @@ static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *
RNA_string_set(op->ptr, "query", ac.ads->searchstr);
/* defer to popup */
- return WM_operator_props_popup(C, op, evt);
+ return WM_operator_props_popup(C, op, event);
}
/* find_exec() - Called to set the value */
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 2ab809c3633..7adddf8f4ae 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -762,9 +762,9 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
MarkerMove *mm = op->customdata;
TimeMarker *marker, *selmarker = NULL;
- const int offs = RNA_int_get(op->ptr, "frames");
+ const int ofs = RNA_int_get(op->ptr, "frames");
char str[UI_MAX_DRAW_STR];
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
int totmark;
const bool use_time = ed_marker_move_use_time(mm);
@@ -776,27 +776,27 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
}
if (hasNumInput(&mm->num)) {
- outputNumInput(&mm->num, str_offs, &scene->unit);
+ outputNumInput(&mm->num, str_ofs, &scene->unit);
}
else if (use_time) {
- BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs));
+ BLI_snprintf(str_ofs, sizeof(str_ofs), "%.2f", FRA2TIME(ofs));
}
else {
- BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs);
+ BLI_snprintf(str_ofs, sizeof(str_ofs), "%d", ofs);
}
if (totmark == 1 && selmarker) {
/* we print current marker value */
if (use_time) {
BLI_snprintf(
- str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs);
+ str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_ofs);
}
else {
- BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_offs);
+ BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_ofs);
}
}
else {
- BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_offs);
+ BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_ofs);
}
ED_area_status_text(CTX_wm_area(C), str);
@@ -907,12 +907,12 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
#endif
MarkerMove *mm = op->customdata;
TimeMarker *marker;
- int a, offs;
+ int a, ofs;
- offs = RNA_int_get(op->ptr, "frames");
+ ofs = RNA_int_get(op->ptr, "frames");
for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
- marker->frame = mm->oldframe[a] + offs;
+ marker->frame = mm->oldframe[a] + ofs;
a++;
}
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index b344e67f62d..653bd72b364 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -173,15 +173,11 @@ static PanelType *fmodifier_panel_register(ARegionType *region_type,
PanelTypePollFn poll,
const char *id_prefix)
{
- /* Get the name for the modifier's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
/* Intentionally leave the label field blank. The header is filled with buttons. */
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name);
BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -215,13 +211,9 @@ static PanelType *fmodifier_subpanel_register(ARegionType *region_type,
PanelTypePollFn poll,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -305,6 +297,7 @@ static void fmodifier_frame_range_draw(const bContext *C, Panel *panel)
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
FModifier *fcm = (FModifier *)ptr->data;
uiLayoutSetActive(layout, fcm->flag & FMODIFIER_FLAG_RANGERESTRICT);
@@ -478,6 +471,7 @@ static void fn_generator_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, ptr, "function_type", 0, "", ICON_NONE);
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_additive", 0, NULL, ICON_NONE);
@@ -698,6 +692,7 @@ static void envelope_panel_draw(const bContext *C, Panel *panel)
FMod_Envelope *env = (FMod_Envelope *)fcm->data;
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* General settings. */
col = uiLayoutColumn(layout, true);
@@ -792,6 +787,7 @@ static void limits_panel_draw(const bContext *C, Panel *panel)
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* Minimums. */
col = uiLayoutColumn(layout, false);
@@ -853,6 +849,7 @@ static void stepped_panel_draw(const bContext *C, Panel *panel)
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* Stepping Settings. */
col = uiLayoutColumn(layout, false);
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index b9ef69cf8bd..06107b6fee6 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -49,6 +49,7 @@
#include "GPU_immediate.h"
#include "GPU_state.h"
+#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -691,13 +692,16 @@ static void draw_keylist(View2D *v2d,
bool channelLocked,
int saction_flag)
{
+ if (keys == NULL) {
+ return;
+ }
+
const float icon_sz = U.widget_unit * 0.5f * yscale_fac;
const float half_icon_sz = 0.5f * icon_sz;
- const float quarter_icon_sz = 0.25f * icon_sz;
const float smaller_sz = 0.35f * icon_sz;
const float ipo_sz = 0.1f * icon_sz;
-
- GPU_blend(GPU_BLEND_ALPHA);
+ const float gpencil_sz = smaller_sz * 0.8f;
+ const float screenspace_margin = (0.35f * (float)UI_UNIT_X) / UI_view2d_scale_get_x(v2d);
/* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */
/* TODO: allow this opacity factor to be themed? */
@@ -705,175 +709,167 @@ static void draw_keylist(View2D *v2d,
/* Show interpolation and handle type? */
bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0;
-
/* draw keyblocks */
- if (keys) {
- float sel_color[4], unsel_color[4];
- float sel_mhcol[4], unsel_mhcol[4];
- float ipo_color[4], ipo_color_mix[4];
-
- /* cache colors first */
- UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
- UI_GetThemeColor4fv(TH_STRIP, unsel_color);
- UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color);
-
- sel_color[3] *= alpha;
- unsel_color[3] *= alpha;
- ipo_color[3] *= alpha;
-
- copy_v4_v4(sel_mhcol, sel_color);
- sel_mhcol[3] *= 0.8f;
- copy_v4_v4(unsel_mhcol, unsel_color);
- unsel_mhcol[3] *= 0.8f;
- copy_v4_v4(ipo_color_mix, ipo_color);
- ipo_color_mix[3] *= 0.5f;
-
- uint block_len = 0;
- uint gpencil_len = 0;
- LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
- if (actkeyblock_get_valid_hold(ab)) {
- block_len++;
- }
- if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
- block_len++;
- }
- if ((ab->next != NULL) && (ab->block.flag & ACTKEYBLOCK_FLAG_GPENCIL)) {
- gpencil_len++;
+ float sel_color[4], unsel_color[4];
+ float sel_mhcol[4], unsel_mhcol[4];
+ float ipo_color[4], ipo_color_mix[4];
+
+ /* cache colors first */
+ UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
+ UI_GetThemeColor4fv(TH_STRIP, unsel_color);
+ UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color);
+
+ sel_color[3] *= alpha;
+ unsel_color[3] *= alpha;
+ ipo_color[3] *= alpha;
+
+ copy_v4_v4(sel_mhcol, sel_color);
+ sel_mhcol[3] *= 0.8f;
+ copy_v4_v4(unsel_mhcol, unsel_color);
+ unsel_mhcol[3] *= 0.8f;
+ copy_v4_v4(ipo_color_mix, ipo_color);
+ ipo_color_mix[3] *= 0.5f;
+
+ LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
+ /* Draw grease pencil bars between keyframes. */
+ if ((ab->next != NULL) && (ab->block.flag & ACTKEYBLOCK_FLAG_GPENCIL)) {
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ float size = 1.0f;
+ switch (ab->next->key_type) {
+ case BEZT_KEYTYPE_BREAKDOWN:
+ case BEZT_KEYTYPE_MOVEHOLD:
+ case BEZT_KEYTYPE_JITTER:
+ size *= 0.5f;
+ break;
+ case BEZT_KEYTYPE_KEYFRAME:
+ size *= 0.8f;
+ break;
+ default:
+ break;
}
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = ab->cfra,
+ .xmax = min_ff(ab->next->cfra - (screenspace_margin * size), ab->next->cfra),
+ .ymin = ypos - gpencil_sz,
+ .ymax = ypos + gpencil_sz,
+ },
+ true,
+ 0.25f * (float)UI_UNIT_X,
+ (ab->block.sel) ? sel_mhcol : unsel_mhcol);
}
-
- if ((block_len > 0) || (gpencil_len > 0)) {
- GPUVertFormat *format = immVertexFormat();
- uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
-
- /* Normal Dopesheet. */
- if (block_len > 0) {
- immBegin(GPU_PRIM_TRIS, 6 * block_len);
- LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
- int valid_hold = actkeyblock_get_valid_hold(ab);
- if (valid_hold != 0) {
- if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* draw "moving hold" long-keyframe block - slightly smaller */
- immRectf_fast_with_color(pos_id,
- color_id,
- ab->cfra,
- ypos - smaller_sz,
- ab->next->cfra,
- ypos + smaller_sz,
- (ab->block.sel) ? sel_mhcol : unsel_mhcol);
- }
- else {
- /* draw standard long-keyframe block */
- immRectf_fast_with_color(pos_id,
- color_id,
- ab->cfra,
- ypos - half_icon_sz,
- ab->next->cfra,
- ypos + half_icon_sz,
- (ab->block.sel) ? sel_color : unsel_color);
- }
- }
- if (show_ipo && actkeyblock_is_valid(ab) &&
- (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
- /* draw an interpolation line */
- immRectf_fast_with_color(
- pos_id,
- color_id,
- ab->cfra,
- ypos - ipo_sz,
- ab->next->cfra,
- ypos + ipo_sz,
- (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color);
- }
+ else {
+ /* Draw other types. */
+ UI_draw_roundbox_corner_set(UI_CNR_NONE);
+
+ int valid_hold = actkeyblock_get_valid_hold(ab);
+ if (valid_hold != 0) {
+ if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* draw "moving hold" long-keyframe block - slightly smaller */
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = ab->cfra,
+ .xmax = ab->next->cfra,
+ .ymin = ypos - smaller_sz,
+ .ymax = ypos + smaller_sz,
+ },
+ true,
+ 3.0f,
+ (ab->block.sel) ? sel_mhcol : unsel_mhcol);
}
- }
- /* Grease Pencil Dopesheet. */
- else {
- immBegin(GPU_PRIM_TRIS, 6 * gpencil_len);
- LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
- if (ab->next == NULL) {
- continue;
- }
- immRectf_fast_with_color(pos_id,
- color_id,
- ab->cfra,
- ypos - quarter_icon_sz,
- ab->next->cfra,
- ypos + quarter_icon_sz,
- (ab->block.sel) ? sel_mhcol : unsel_mhcol);
+ else {
+ /* draw standard long-keyframe block */
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = ab->cfra,
+ .xmax = ab->next->cfra,
+ .ymin = ypos - half_icon_sz,
+ .ymax = ypos + half_icon_sz,
+ },
+ true,
+ 3.0f,
+ (ab->block.sel) ? sel_color : unsel_color);
}
}
- immEnd();
- immUnbindProgram();
+ if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
+ /* draw an interpolation line */
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = ab->cfra,
+ .xmax = ab->next->cfra,
+ .ymin = ypos - ipo_sz,
+ .ymax = ypos + ipo_sz,
+ },
+ true,
+ 3.0f,
+ (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color);
+ }
}
}
- if (keys) {
- /* count keys */
- uint key_len = 0;
- LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
- /* Optimization: if keyframe doesn't appear within 5 units (screenspace)
- * in visible area, don't draw.
- * This might give some improvements,
- * since we current have to flip between view/region matrices.
- */
- if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
- key_len++;
- }
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ /* count keys */
+ uint key_len = 0;
+ LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
+ /* Optimization: if keyframe doesn't appear within 5 units (screenspace)
+ * in visible area, don't draw.
+ * This might give some improvements,
+ * since we current have to flip between view/region matrices.
+ */
+ if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
+ key_len++;
}
+ }
- if (key_len > 0) {
- /* draw keys */
- GPUVertFormat *format = immVertexFormat();
- uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color_id = GPU_vertformat_attr_add(
- format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- uint outline_color_id = GPU_vertformat_attr_add(
- format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
-
- GPU_program_point_size(true);
- immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
- immUniform1f("outline_scale", 1.0f);
- immUniform2f(
- "ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
- immBegin(GPU_PRIM_POINTS, key_len);
-
- short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
-
- LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
- if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
- if (show_ipo) {
- handle_type = ak->handle_type;
- }
- if (saction_flag & SACTION_SHOW_EXTREMES) {
- extreme_type = ak->extreme_type;
- }
+ if (key_len > 0) {
+ /* draw keys */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(
+ format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint outline_color_id = GPU_vertformat_attr_add(
+ format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+
+ GPU_program_point_size(true);
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ immUniform1f("outline_scale", 1.0f);
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
+ immBegin(GPU_PRIM_POINTS, key_len);
+
+ short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
- draw_keyframe_shape(ak->cfra,
- ypos,
- icon_sz,
- (ak->sel & SELECT),
- ak->key_type,
- KEYFRAME_SHAPE_BOTH,
- alpha,
- pos_id,
- size_id,
- color_id,
- outline_color_id,
- flags_id,
- handle_type,
- extreme_type);
+ LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
+ if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
+ if (show_ipo) {
+ handle_type = ak->handle_type;
+ }
+ if (saction_flag & SACTION_SHOW_EXTREMES) {
+ extreme_type = ak->extreme_type;
}
- }
- immEnd();
- GPU_program_point_size(false);
- immUnbindProgram();
+ draw_keyframe_shape(ak->cfra,
+ ypos,
+ icon_sz,
+ (ak->sel & SELECT),
+ ak->key_type,
+ KEYFRAME_SHAPE_BOTH,
+ alpha,
+ pos_id,
+ size_id,
+ color_id,
+ outline_color_id,
+ flags_id,
+ handle_type,
+ extreme_type);
+ }
}
+
+ immEnd();
+ GPU_program_point_size(false);
+ immUnbindProgram();
}
GPU_blend(GPU_BLEND_NONE);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index bb5bcd4083e..66ca38ce218 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -552,9 +552,12 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
-/* Helper function for armature separating - remove certain bones from the given armature
- * sel: remove selected bones from the armature, otherwise the unselected bones are removed
- * (ob is not in edit-mode)
+/**
+ * Helper function for armature separating - remove certain bones from the given armature.
+ *
+ * \param ob: Armature object (must not be is not in edit-mode).
+ * \param is_select: remove selected bones from the armature,
+ * otherwise the unselected bones are removed.
*/
static void separate_armature_bones(Main *bmain, Object *ob, const bool is_select)
{
@@ -621,7 +624,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
bool ok = false;
/* set wait cursor in case this takes a while */
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
@@ -706,7 +709,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
MEM_freeN(bases);
/* Recalculate/redraw + cleanup */
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
if (ok) {
BKE_report(op->reports, RPT_INFO, "Separated bones");
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 60fe8ee7dee..226253cc063 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -644,8 +644,8 @@ static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12)
static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5)
{
- const int offs = 4 * hits12;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
+ const int ofs = 4 * hits12;
+ memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -704,17 +704,12 @@ static EditBone *get_nearest_editbonepoint(
goto cache_end;
}
else if (hits12 > 0) {
- int offs;
+ int ofs;
- offs = 4 * hits12;
+ ofs = 4 * hits12;
BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
- const int hits5 = view3d_opengl_select_with_id_filter(vc,
- buffer + offs,
- MAXPICKBUF - offs,
- &rect,
- select_mode,
- select_filter,
- select_id_ignore);
+ const int hits5 = view3d_opengl_select_with_id_filter(
+ vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter, select_id_ignore);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 78bce8679bb..e65871c0896 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -476,9 +476,9 @@ static int pose_clear_paths_exec(bContext *C, wmOperator *op)
}
/* operator callback/wrapper */
-static int pose_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+static int pose_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
+ if ((event->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
RNA_boolean_set(op->ptr, "only_selected", true);
}
return pose_clear_paths_exec(C, op);
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 45f623f3a9d..dd90f9f2cc3 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1321,10 +1321,10 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
}
/* specially handle events for searching */
-static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, ushort event, char ascii)
+static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, ushort event_type, char ascii)
{
/* try doing some form of string manipulation first */
- switch (event) {
+ switch (event_type) {
case EVT_BACKSPACEKEY:
if (pld->searchstr[0] && pld->search_cursor) {
short len = strlen(pld->searchstr);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index d636f0d68af..93d36abe792 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -873,12 +873,12 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&pso->num, str_offs, &scene->unit);
+ outputNumInput(&pso->num, str_ofs, &scene->unit);
BLI_snprintf(
- status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
+ status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str);
}
else {
BLI_snprintf(status_str,
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 0593cedb5a1..33ef6a5d026 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1359,7 +1359,7 @@ static int separate_exec(bContext *C, wmOperator *op)
int error_generic;
} status = {0};
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
@@ -1426,7 +1426,7 @@ static int separate_exec(bContext *C, wmOperator *op)
status.changed++;
}
MEM_freeN(bases);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
if (status.unselected == bases_len) {
BKE_report(op->reports, RPT_ERROR, "No point was selected");
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 1e91edbb3c0..47ae90acb74 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRC
annotate_paint.c
drawgpencil.c
editaction_gpencil.c
+ gpencil_add_lineart.c
gpencil_add_monkey.c
gpencil_add_stroke.c
gpencil_armature.c
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index c8bd38d58fe..e9817f82090 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -2093,7 +2093,7 @@ static void annotation_draw_apply_event(
p->mval[1] = (float)event->mval[1] - y;
/* Key to toggle stabilization. */
- if (event->shift > 0 && p->paintmode == GP_PAINTMODE_DRAW) {
+ if (event->shift && p->paintmode == GP_PAINTMODE_DRAW) {
/* Using permanent stabilization, shift will deactivate the flag. */
if (p->flags & GP_PAINTFLAG_USE_STABILIZER) {
if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
@@ -2108,7 +2108,7 @@ static void annotation_draw_apply_event(
}
}
/* verify key status for straight lines */
- else if ((event->ctrl > 0) || (event->alt > 0)) {
+ else if (event->ctrl || event->alt) {
if (p->straight[0] == 0) {
int dx = abs((int)(p->mval[0] - p->mvalo[0]));
int dy = abs((int)(p->mval[1] - p->mvalo[1]));
@@ -2348,7 +2348,7 @@ static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *ev
p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP;
annotation_draw_toggle_stabilizer_cursor(p, true);
}
- else if (event->shift > 0) {
+ else if (event->shift) {
p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
annotation_draw_toggle_stabilizer_cursor(p, true);
}
diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c
new file mode 100644
index 00000000000..71253635ea8
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_add_lineart.c
@@ -0,0 +1,120 @@
+/*
+ * 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) 2017 Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup edgpencil
+ */
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_gpencil.h"
+
+/* Definition of the most important info from a color */
+typedef struct ColorTemplate {
+ const char *name;
+ float line[4];
+ float fill[4];
+} ColorTemplate;
+
+/* Add color an ensure duplications (matched by name) */
+static int gpencil_lineart_material(Main *bmain,
+ Object *ob,
+ const ColorTemplate *pct,
+ const bool fill)
+{
+ short *totcol = BKE_object_material_len_p(ob);
+ Material *ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = BKE_gpencil_material(ob, i + 1);
+ if (STREQ(ma->id.name, pct->name)) {
+ return i;
+ }
+ }
+
+ int idx;
+
+ /* create a new one */
+ ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
+
+ copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
+
+ copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+ srgb_to_linearrgb_v4(ma->gp_style->fill_rgba, ma->gp_style->fill_rgba);
+
+ if (fill) {
+ ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+
+ return idx;
+}
+
+/* ***************************************************************** */
+/* Color Data */
+
+static const ColorTemplate gp_stroke_material_black = {
+ "Black",
+ {0.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+/* ***************************************************************** */
+/* LineArt API */
+
+/* Add a Simple LineArt setup. */
+void ED_gpencil_create_lineart(bContext *C, Object *ob)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ /* create colors */
+ int color_black = gpencil_lineart_material(bmain, ob, &gp_stroke_material_black, false);
+
+ /* set first color as active and in brushes */
+ ob->actcol = color_black + 1;
+
+ /* layers */
+ bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
+
+ /* frames */
+ BKE_gpencil_frame_addnew(lines, CFRA);
+
+ /* update depsgraph */
+ /* To trigger modifier update, this is still needed although we don't have any strokes. */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 039bc50fcc9..fd2758c8a08 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1420,7 +1420,7 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot)
/* ********************** Change Layer ***************************** */
-static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index b03d2c6e795..4bbd475dd2c 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3095,7 +3095,6 @@ static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *op)
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
float *cursor = scene->cursor.location;
float centroid[3] = {0.0f};
@@ -3125,7 +3124,7 @@ static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c
index 0f9a8c93df9..e766a410889 100644
--- a/source/blender/editors/gpencil/gpencil_edit_curve.c
+++ b/source/blender/editors/gpencil/gpencil_edit_curve.c
@@ -131,7 +131,7 @@ void GPENCIL_OT_stroke_enter_editcurve_mode(wmOperatorType *ot)
"Error Threshold",
"Threshold on the maximum deviation from the actual stroke",
FLT_MIN,
- 10.f);
+ 10.0f);
RNA_def_property_ui_range(prop, FLT_MIN, 10.0f, 0.1f, 5);
}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 406daf9f92e..4749f40fac5 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -55,6 +55,7 @@
#include "BKE_screen.h"
#include "ED_gpencil.h"
+#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
@@ -542,12 +543,18 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4])
if (gpl == tgpf->gpl) {
if ((gpl->actframe == NULL) || (gpl->actframe->framenum != tgpf->active_cfra)) {
short add_frame_mode;
- if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- add_frame_mode = GP_GETFRAME_ADD_COPY;
+ if (IS_AUTOKEY_ON(tgpf->scene)) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ }
+ else {
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+ }
}
else {
- add_frame_mode = GP_GETFRAME_ADD_NEW;
+ add_frame_mode = GP_GETFRAME_USE_PREV;
}
+
BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, add_frame_mode);
}
}
@@ -1456,7 +1463,10 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
tgpf->done = true;
/* Get frame or create a new one. */
- tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW);
+ tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl,
+ tgpf->active_cfra,
+ IS_AUTOKEY_ON(tgpf->scene) ? GP_GETFRAME_ADD_NEW :
+ GP_GETFRAME_USE_PREV);
/* Set frame as selected. */
tgpf->gpf->flag |= GP_FRAME_SELECT;
@@ -1700,6 +1710,15 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op)
tgpf->mat = ma;
+ /* Untag strokes to be sure nothing is pending due any canceled process. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpf->gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ gps->flag &= ~GP_STROKE_TAG;
+ }
+ }
+ }
+
/* check whether the material was newly added */
if (totcol != tgpf->ob->totcol) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
@@ -2064,6 +2083,12 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
estate = OPERATOR_CANCELLED;
break;
case LEFTMOUSE:
+ if (!IS_AUTOKEY_ON(tgpf->scene) && (!is_multiedit) && (tgpf->gpl->actframe == NULL)) {
+ BKE_report(op->reports, RPT_INFO, "No available frame for creating stroke");
+ estate = OPERATOR_CANCELLED;
+ break;
+ }
+
/* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || (!help_lines)) {
ARegion *region = BKE_area_find_region_xy(
@@ -2088,17 +2113,24 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
gpencil_stroke_convertcoords_tpoint(
tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x);
+ /* Hash of selected frames.*/
+ GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64);
+
/* If not multiframe and there is no frame in CFRA for the active layer, create
- * a new frame before to make the hash function can find something. */
+ * a new frame. */
if (!is_multiedit) {
tgpf->gpf = BKE_gpencil_layer_frame_get(
- tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW);
+ tgpf->gpl,
+ tgpf->active_cfra,
+ IS_AUTOKEY_ON(tgpf->scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV);
tgpf->gpf->flag |= GP_FRAME_SELECT;
- }
- /* Hash of selected frames.*/
- GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64);
- BKE_gpencil_frame_selected_hash(tgpf->gpd, frame_list);
+ BLI_ghash_insert(
+ frame_list, POINTER_FROM_INT(tgpf->active_cfra), tgpf->gpl->actframe);
+ }
+ else {
+ BKE_gpencil_frame_selected_hash(tgpf->gpd, frame_list);
+ }
/* Loop all frames. */
wmWindow *win = CTX_wm_window(C);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 7c541f61d75..1281f1392d8 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -435,16 +435,16 @@ static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgp
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
-/* Helper: Get previous keyframe. */
+/* Helper: Get previous keyframe (exclude breakdown type). */
static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra)
{
if (gpl->actframe != NULL && gpl->actframe->framenum < cfra &&
- gpl->actframe->key_type == BEZT_KEYTYPE_KEYFRAME) {
+ gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN) {
return gpl->actframe;
}
LISTBASE_FOREACH_BACKWARD (bGPDframe *, gpf, &gpl->frames) {
- if (gpf->key_type != BEZT_KEYTYPE_KEYFRAME) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
continue;
}
if (gpf->framenum >= cfra) {
@@ -456,11 +456,11 @@ static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra)
return NULL;
}
-/* Helper: Get next keyframe. */
+/* Helper: Get next keyframe (exclude breakdown type). */
static bGPDframe *gpencil_get_next_keyframe(bGPDlayer *gpl, int cfra)
{
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
- if (gpf->key_type != BEZT_KEYTYPE_KEYFRAME) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
continue;
}
if (gpf->framenum <= cfra) {
@@ -599,10 +599,10 @@ static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *
BLI_strncpy(msg_str, TIP_("GPencil Interpolation: "), UI_MAX_DRAW_STR);
if (hasNumInput(&p->num)) {
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&p->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs);
+ outputNumInput(&p->num, str_ofs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_ofs);
}
else {
BLI_snprintf(status_str,
@@ -760,7 +760,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
Scene *scene = CTX_data_scene(C);
tGPDinterpolate *tgpi = NULL;
- /* cannot interpolate if not between 2 frames */
+ /* Cannot interpolate if not between 2 frames. */
int cfra = CFRA;
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra);
@@ -768,7 +768,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
BKE_report(
op->reports,
RPT_ERROR,
- "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ "Cannot find valid keyframes to interpolate (Breakdowns keyframes are not allowed)");
return OPERATOR_CANCELLED;
}
@@ -1260,7 +1260,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
BKE_report(
op->reports,
RPT_ERROR,
- "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ "Cannot find valid keyframes to interpolate (Breakdowns keyframes are not allowed)");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c
index 7e6b42f284b..b7ed77801c0 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.c
+++ b/source/blender/editors/gpencil/gpencil_mesh.c
@@ -251,7 +251,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
gpd->draw_mode = (project_type == GP_REPROJECT_KEEP) ? GP_DRAWMODE_3D : GP_DRAWMODE_2D;
/* Set cursor to indicate working. */
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
GP_SpaceConversion gsc = {NULL};
SnapObjectContext *sctx = NULL;
@@ -385,7 +385,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
/* Reset cursor. */
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
/* done */
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 974f51ff90b..1217a3a7e8f 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -67,6 +67,7 @@
#include "ED_clip.h"
#include "ED_gpencil.h"
+#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -2155,6 +2156,10 @@ static void gpencil_paint_initstroke(tGPsdata *p,
continue;
}
+ if (!IS_AUTOKEY_ON(scene) && (gpl->actframe == NULL)) {
+ continue;
+ }
+
/* Add a new frame if needed (and based off the active frame,
* as we need some existing strokes to erase)
*
@@ -2164,7 +2169,8 @@ static void gpencil_paint_initstroke(tGPsdata *p,
*/
if (gpl->actframe && gpl->actframe->strokes.first) {
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV;
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, frame_mode);
}
has_layer_to_erase = true;
break;
@@ -2187,11 +2193,16 @@ static void gpencil_paint_initstroke(tGPsdata *p,
/* Drawing Modes - Add a new frame if needed on the active layer */
short add_frame_mode;
- if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- add_frame_mode = GP_GETFRAME_ADD_COPY;
+ if (IS_AUTOKEY_ON(scene)) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ }
+ else {
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+ }
}
else {
- add_frame_mode = GP_GETFRAME_ADD_NEW;
+ add_frame_mode = GP_GETFRAME_USE_PREV;
}
bool need_tag = p->gpl->actframe == NULL;
@@ -2206,6 +2217,10 @@ static void gpencil_paint_initstroke(tGPsdata *p,
if (G.debug & G_DEBUG) {
printf("Error: No frame created (gpencil_paint_init)\n");
}
+ if (!IS_AUTOKEY_ON(scene)) {
+ BKE_report(p->reports, RPT_INFO, "No available frame for creating stroke");
+ }
+
return;
}
p->gpf->flag |= GP_FRAME_PAINT;
@@ -2469,6 +2484,8 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
return 0;
}
+ p->reports = op->reports;
+
/* init painting data */
gpencil_paint_initstroke(p, paintmode, CTX_data_ensure_evaluated_depsgraph(C));
if (p->status == GP_STATUS_ERROR) {
@@ -2483,8 +2500,6 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
p->keymodifier = -1;
}
- p->reports = op->reports;
-
/* everything is now setup ok */
return 1;
}
@@ -2835,7 +2850,7 @@ static void gpencil_draw_apply_event(bContext *C,
/* verify direction for straight lines and guides */
if ((is_speed_guide) ||
- ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false))) {
+ (event->alt && (RNA_boolean_get(op->ptr, "disable_straight") == false))) {
if (p->straight == 0) {
int dx = (int)fabsf(p->mval[0] - p->mvali[0]);
int dy = (int)fabsf(p->mval[1] - p->mvali[1]);
@@ -2876,13 +2891,13 @@ static void gpencil_draw_apply_event(bContext *C,
/* special eraser modes */
if (p->paintmode == GP_PAINTMODE_ERASER) {
- if (event->shift > 0) {
+ if (event->shift) {
p->flags |= GP_PAINTFLAG_HARD_ERASER;
}
else {
p->flags &= ~GP_PAINTFLAG_HARD_ERASER;
}
- if (event->alt > 0) {
+ if (event->alt) {
p->flags |= GP_PAINTFLAG_STROKE_ERASER;
}
else {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 12d399f32ca..dfff0ce639e 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -71,6 +71,7 @@
#include "RNA_enum_types.h"
#include "ED_gpencil.h"
+#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -465,10 +466,10 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
GP_STROKE_BOX,
GP_STROKE_POLYLINE)) {
if (hasNumInput(&tgpi->num)) {
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&tgpi->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ outputNumInput(&tgpi->num, str_ofs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_ofs);
}
else {
if (tgpi->flag == IN_PROGRESS) {
@@ -1253,9 +1254,18 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
tGPDprimitive *tgpi = NULL;
+ if (!IS_AUTOKEY_ON(scene)) {
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ if ((gpl == NULL) || (gpl->actframe == NULL)) {
+ BKE_report(op->reports, RPT_INFO, "No available frame for creating stroke");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
/* initialize operator runtime data */
gpencil_primitive_init(C, op);
tgpi = op->customdata;
@@ -1310,11 +1320,16 @@ static void gpencil_primitive_interaction_end(bContext *C,
/* insert keyframes as required... */
short add_frame_mode;
- if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- add_frame_mode = GP_GETFRAME_ADD_COPY;
+ if (IS_AUTOKEY_ON(tgpi->scene)) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ }
+ else {
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+ }
}
else {
- add_frame_mode = GP_GETFRAME_ADD_NEW;
+ add_frame_mode = GP_GETFRAME_USE_PREV;
}
bool need_tag = tgpi->gpl->actframe == NULL;
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 0d3ab9011d6..9666aca5254 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -73,6 +73,7 @@
#include "UI_view2d.h"
#include "ED_gpencil.h"
+#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -1019,7 +1020,11 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
if (gpl == NULL) {
gpl = CTX_data_active_gpencil_layer(C);
}
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(
+ gpl, CFRA, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV);
+ if (gpf == NULL) {
+ continue;
+ }
/* Make a new stroke */
new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true);
@@ -1334,6 +1339,10 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso
/* go through each layer, and ensure that we've got a valid frame to use */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ if (!IS_AUTOKEY_ON(scene) && (gpl->actframe == NULL)) {
+ continue;
+ }
+
/* only editable and visible layers are considered */
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
@@ -1343,7 +1352,7 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame.
*/
- if (gpf->framenum != cfra) {
+ if ((IS_AUTOKEY_ON(scene)) && (gpf->framenum != cfra)) {
BKE_gpencil_frame_addcopy(gpl, cfra);
/* Need tag to recalculate evaluated data to avoid crashes. */
DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 2415c85e299..4b440aa7367 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -55,7 +55,6 @@ struct FModifier;
struct bAction;
struct uiBlock;
-struct uiLayout;
struct PointerRNA;
struct PropertyRNA;
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 56494f87bfe..21d8a28e2c9 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -64,6 +64,10 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc,
float *scale,
float *angle);
+bool ED_space_clip_get_position(struct SpaceClip *sc,
+ struct ARegion *ar,
+ int mval[2],
+ float fpos[2]);
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
int mval[2],
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 7538dac1354..983ae94b637 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -145,6 +145,13 @@ void ED_fileselect_exit(struct wmWindowManager *wm,
struct SpaceFile *sfile);
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
+struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
+
+/* Activate the file that corresponds to the given ID.
+ * Pass deferred=true to wait for the next refresh before activating. */
+void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
+ struct ID *asset_id,
+ const bool deferred);
void ED_fileselect_window_params_get(const struct wmWindow *win,
int win_size[2],
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 2fbf280475b..f3b5abb1072 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -250,6 +250,7 @@ void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]);
void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]);
+void ED_gpencil_create_lineart(struct bContext *C, struct Object *ob);
/* ------------ Object Utilities ------------ */
struct Object *ED_gpencil_add_object(struct bContext *C,
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index b139b0765a3..ec525806b81 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -53,6 +53,10 @@ void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
+bool ED_space_image_get_position(struct SpaceImage *sima,
+ struct ARegion *region,
+ int mval[2],
+ float fpos[2]);
bool ED_space_image_color_sample(
struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index ea2383457c2..67a50b83bd6 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -121,6 +121,11 @@ void ED_node_composite_job(const struct bContext *C,
void ED_operatormacros_node(void);
/* node_view.c */
+bool ED_space_node_get_position(struct Main *bmain,
+ struct SpaceNode *snode,
+ struct ARegion *region,
+ const int mval[2],
+ float fpos[2]);
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 5dfce6071f0..0767ce21382 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -163,8 +163,8 @@ extern struct EnumPropertyItem prop_make_parent_types[];
bool ED_object_parent_set(struct ReportList *reports,
const struct bContext *C,
struct Scene *scene,
- struct Object *ob,
- struct Object *par,
+ struct Object *const ob,
+ struct Object *const par,
int partype,
const bool xmirror,
const bool keep_transform,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 61e1f0fdf7d..b3205acb8ee 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -52,7 +52,6 @@ struct rcti;
struct uiBlock;
struct uiLayout;
struct wmKeyConfig;
-struct wmMsgBus;
struct wmMsgSubscribeKey;
struct wmMsgSubscribeValue;
struct wmNotifier;
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index fc474ea464d..1a3aa7e5496 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -55,6 +55,7 @@ void ED_spacetype_userpref(void);
void ED_spacetype_clip(void);
void ED_spacetype_statusbar(void);
void ED_spacetype_topbar(void);
+void ED_spacetype_spreadsheet(void);
/* calls for instancing and freeing spacetype static data
* called in WM_init_exit */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 5620d39ab16..d23daf7f0e3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2078,7 +2078,10 @@ void uiTemplatePalette(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
bool colors);
-void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+void uiTemplateCryptoPicker(uiLayout *layout,
+ struct PointerRNA *ptr,
+ const char *propname,
+ int icon);
void uiTemplateLayers(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 82bcd5d7eb4..421019bebb8 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesdna
../../makesrna
../../python
+ ../../render
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 53a04ec9db5..91c19ff2850 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -567,7 +567,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
/* Keyframes */
if (but->flag & UI_BUT_ANIMATED_KEY) {
- /* replace/delete keyfraemes */
+ /* Replace/delete keyframes. */
if (is_array_component) {
uiItemBooleanO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"),
@@ -936,6 +936,12 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
ICON_NONE,
"UI_OT_copy_data_path_button");
+ uiItemBooleanO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Full Data Path"),
+ ICON_NONE,
+ "UI_OT_copy_data_path_button",
+ "full_path",
+ true);
if (ptr->owner_id && !is_whole_array &&
ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index d10cdc207c2..40cfcaea883 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -120,7 +120,7 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect,
};
GPUBatch *batch = ui_batch_roundbox_widget_get();
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
- GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float(*)[4]) & widget_params);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 11, (const float(*)[4]) & widget_params);
GPU_blend(GPU_BLEND_ALPHA);
GPU_batch_draw(batch);
GPU_blend(GPU_BLEND_NONE);
@@ -2376,7 +2376,7 @@ void ui_draw_dropshadow(
GPUBatch *batch = ui_batch_roundbox_shadow_get();
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW);
- GPU_batch_uniform_4fv_array(batch, "parameters", 4, (float(*)[4]) & widget_params);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 4, (const float(*)[4]) & widget_params);
GPU_batch_uniform_1f(batch, "alpha", 1.0f - visibility);
GPU_batch_draw(batch);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index de39484bc1e..fb8d32b3b84 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -103,26 +103,41 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
*/
/** \name Generic Shared Functions
* \{ */
-
-void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *region, const char *name)
+static void eyedropper_draw_cursor_text_ex(const int x, const int y, const char *name)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- wmWindow *win = CTX_wm_window(C);
- int x = win->eventstate->x;
- int y = win->eventstate->y;
+
const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
- if ((name[0] == '\0') || (BLI_rcti_isect_pt(&region->winrct, x, y) == false)) {
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y + U.widget_unit, name, col_fg, col_bg);
+}
+
+void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name)
+{
+ if (name[0] == '\0') {
return;
}
- x = x - region->winrct.xmin;
- y = y - region->winrct.ymin;
+ const int x = window->eventstate->x;
+ const int y = window->eventstate->y;
- y += U.widget_unit;
+ eyedropper_draw_cursor_text_ex(x, y, name);
+}
+
+void eyedropper_draw_cursor_text_region(const struct bContext *C,
+ const ARegion *region,
+ const char *name)
+{
+ wmWindow *win = CTX_wm_window(C);
+ const int x = win->eventstate->x - region->winrct.xmin;
+ const int y = win->eventstate->y - region->winrct.ymin;
+
+ if ((name[0] == '\0') || (BLI_rcti_isect_pt(&region->winrct, x, y) == false)) {
+ return;
+ }
- UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
+ eyedropper_draw_cursor_text_ex(x, y, name);
}
/**
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 5af290db037..4ae6f66281f 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -31,10 +31,15 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_string.h"
#include "BKE_context.h"
+#include "BKE_cryptomatte.h"
+#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -42,6 +47,7 @@
#include "UI_interface.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -53,6 +59,11 @@
#include "ED_clip.h"
#include "ED_image.h"
#include "ED_node.h"
+#include "ED_screen.h"
+
+#include "RE_pipeline.h"
+
+#include "RE_pipeline.h"
#include "interface_eyedropper_intern.h"
@@ -71,13 +82,22 @@ typedef struct Eyedropper {
float accum_col[3];
int accum_tot;
- bool use_accum;
+ void *draw_handle_sample_text;
+ char sample_text[MAX_NAME];
+
+ bNode *crypto_node;
+ struct CryptomatteSession *cryptomatte_session;
} Eyedropper;
+static void eyedropper_draw_cb(const wmWindow *window, void *arg)
+{
+ Eyedropper *eye = arg;
+ eyedropper_draw_cursor_text_window(window, eye->sample_text);
+}
+
static bool eyedropper_init(bContext *C, wmOperator *op)
{
Eyedropper *eye = MEM_callocN(sizeof(Eyedropper), __func__);
- eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate");
uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0;
@@ -96,6 +116,15 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
float col[4];
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
+ if (ELEM(eye->ptr.type, &RNA_CompositorNodeCryptomatteV2, &RNA_CompositorNodeCryptomatte)) {
+ eye->crypto_node = (bNode *)eye->ptr.data;
+ eye->cryptomatte_session = ntreeCompositCryptomatteSession(eye->crypto_node);
+ eye->draw_handle_sample_text = WM_draw_cb_activate(CTX_wm_window(C), eyedropper_draw_cb, eye);
+ }
+ else {
+ eye->crypto_node = NULL;
+ }
+
if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;
@@ -115,16 +144,169 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
static void eyedropper_exit(bContext *C, wmOperator *op)
{
- WM_cursor_modal_restore(CTX_wm_window(C));
+ Eyedropper *eye = op->customdata;
+ wmWindow *window = CTX_wm_window(C);
+ WM_cursor_modal_restore(window);
+
+ if (eye->draw_handle_sample_text) {
+ WM_draw_cb_exit(window, eye->draw_handle_sample_text);
+ eye->draw_handle_sample_text = NULL;
+ }
- if (op->customdata) {
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+ if (eye->cryptomatte_session) {
+ BKE_cryptomatte_free(eye->cryptomatte_session);
+ eye->cryptomatte_session = NULL;
}
+
+ MEM_SAFE_FREE(op->customdata);
}
/* *** eyedropper_color_ helper functions *** */
+static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_layer,
+ const char *prefix,
+ const float fpos[2],
+ float r_col[3])
+{
+ if (!render_layer) {
+ return false;
+ }
+
+ const int render_layer_name_len = BLI_strnlen(render_layer->name, sizeof(render_layer->name));
+ if (strncmp(prefix, render_layer->name, render_layer_name_len) != 0) {
+ return false;
+ }
+
+ const int prefix_len = strlen(prefix);
+ if (prefix_len <= render_layer_name_len + 1) {
+ return false;
+ }
+
+ /* RenderResult from images can have no render layer name. */
+ const char *render_pass_name_prefix = render_layer_name_len ?
+ prefix + 1 + render_layer_name_len :
+ prefix;
+
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ if (STRPREFIX(render_pass->name, render_pass_name_prefix) &&
+ !STREQLEN(render_pass->name, render_pass_name_prefix, sizeof(render_pass->name))) {
+ BLI_assert(render_pass->channels == 4);
+ const int x = (int)(fpos[0] * render_pass->rectx);
+ const int y = (int)(fpos[1] * render_pass->recty);
+ const int offset = 4 * (y * render_pass->rectx + x);
+ zero_v3(r_col);
+ r_col[0] = render_pass->rect[offset];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool eyedropper_cryptomatte_sample_fl(
+ bContext *C, Eyedropper *eye, int mx, int my, float r_col[3])
+{
+ bNode *node = eye->crypto_node;
+ NodeCryptomatte *crypto = node ? ((NodeCryptomatte *)node->storage) : NULL;
+
+ if (!crypto) {
+ return false;
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ return false;
+ }
+
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (!ar) {
+ return false;
+ }
+
+ int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ float fpos[2] = {-1.0f, -1.0};
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = sa->spacedata.first;
+ ED_space_image_get_position(sima, ar, mval, fpos);
+ break;
+ }
+ case SPACE_NODE: {
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = sa->spacedata.first;
+ ED_space_node_get_position(bmain, snode, ar, mval, fpos);
+ break;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sc = sa->spacedata.first;
+ ED_space_clip_get_position(sc, ar, mval, fpos);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (fpos[0] < 0.0f || fpos[1] < 0.0f || fpos[0] >= 1.0f || fpos[1] >= 1.0f) {
+ return false;
+ }
+
+ /* CMP_CRYPTOMATTE_SRC_RENDER and CMP_CRYPTOMATTE_SRC_IMAGE require a referenced image/scene to
+ * work properly. */
+ if (!node->id) {
+ return false;
+ }
+
+ bool success = false;
+ /* TODO(jbakker): Migrate this file to cc and use std::string as return param. */
+ char prefix[MAX_NAME + 1];
+ ntreeCompositCryptomatteLayerPrefix(node, prefix, sizeof(prefix) - 1);
+ prefix[MAX_NAME] = '\0';
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ Scene *scene = (Scene *)node->id;
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *re = RE_GetSceneRender(scene);
+
+ if (re) {
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name);
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(
+ render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ RE_ReleaseResult(re);
+ }
+ }
+ else if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ Image *image = (Image *)node->id;
+ BLI_assert(GS(image->id.name) == ID_IM);
+ ImageUser *iuser = &crypto->iuser;
+
+ if (image && image->type == IMA_TYPE_MULTILAYER) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ if (image->rr) {
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(
+ render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+
+ return success;
+}
+
/**
* \brief get the color from the screen.
*
@@ -230,9 +412,16 @@ static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my
{
/* Accumulate color. */
float col[3];
- eyedropper_color_sample_fl(C, mx, my, col);
+ if (eye->crypto_node) {
+ if (!eyedropper_cryptomatte_sample_fl(C, eye, mx, my, col)) {
+ return;
+ }
+ }
+ else {
+ eyedropper_color_sample_fl(C, mx, my, col);
+ }
- if (eye->use_accum) {
+ if (!eye->crypto_node) {
add_v3_v3(eye->accum_col, col);
eye->accum_tot++;
}
@@ -252,6 +441,20 @@ static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my
eyedropper_color_set(C, eye, accum_col);
}
+static void eyedropper_color_sample_text_update(bContext *C, Eyedropper *eye, int mx, int my)
+{
+ float col[3];
+ eye->sample_text[0] = '\0';
+
+ if (eye->cryptomatte_session) {
+ if (eyedropper_cryptomatte_sample_fl(C, eye, mx, my, col)) {
+ BKE_cryptomatte_find_name(
+ eye->cryptomatte_session, col[0], eye->sample_text, sizeof(eye->sample_text));
+ eye->sample_text[sizeof(eye->sample_text) - 1] = '\0';
+ }
+ }
+}
+
static void eyedropper_cancel(bContext *C, wmOperator *op)
{
Eyedropper *eye = op->customdata;
@@ -298,6 +501,11 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* button is pressed so keep sampling */
eyedropper_color_sample(C, eye, event->x, event->y);
}
+
+ if (eye->draw_handle_sample_text) {
+ eyedropper_color_sample_text_update(C, eye, event->x, event->y);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
}
return OPERATOR_RUNNING_MODAL;
@@ -360,11 +568,4 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
- PropertyRNA *prop;
-
- /* Needed for color picking with crypto-matte. */
- prop = RNA_def_boolean(ot->srna, "use_accumulate", true, "Accumulate", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 6a12f550d7c..8c605598cbc 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -77,7 +77,7 @@ typedef struct DataDropper {
static void datadropper_draw_cb(const struct bContext *C, ARegion *region, void *arg)
{
DataDropper *ddr = arg;
- eyedropper_draw_cursor_text(C, region, ddr->name);
+ eyedropper_draw_cursor_text_region(C, region, ddr->name);
}
static int datadropper_init(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index a4adbef0b94..a64fad8c333 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -78,7 +78,7 @@ typedef struct DepthDropper {
static void depthdropper_draw_cb(const struct bContext *C, ARegion *region, void *arg)
{
DepthDropper *ddr = arg;
- eyedropper_draw_cursor_text(C, region, ddr->name);
+ eyedropper_draw_cursor_text_region(C, region, ddr->name);
}
static int depthdropper_init(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
index fd60dcb7c86..96a2c6ed111 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -23,9 +23,10 @@
#pragma once
/* interface_eyedropper.c */
-void eyedropper_draw_cursor_text(const struct bContext *C,
- const struct ARegion *region,
- const char *name);
+void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name);
+void eyedropper_draw_cursor_text_region(const struct bContext *C,
+ const struct ARegion *region,
+ const char *name);
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event);
/* interface_eyedropper_color.c (expose for color-band picker) */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 75ee3300e63..81da54ade9e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -168,12 +168,14 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
#define PIE_MENU_INTERVAL 0.01
#define BUTTON_AUTO_OPEN_THRESH 0.2
#define BUTTON_MOUSE_TOWARDS_THRESH 1.0
-/* pixels to move the cursor to get out of keyboard navigation */
+/** Pixels to move the cursor to get out of keyboard navigation. */
#define BUTTON_KEYNAV_PX_LIMIT 8
-#define MENU_TOWARDS_MARGIN 20 /* margin in pixels */
-#define MENU_TOWARDS_WIGGLE_ROOM 64 /* tolerance in pixels */
-/* drag-lock distance threshold in pixels */
+/** Margin around the menu, use to check if we're moving towards this rectangle (in pixels). */
+#define MENU_TOWARDS_MARGIN 20
+/** Tolerance for closing menus (in pixels). */
+#define MENU_TOWARDS_WIGGLE_ROOM 64
+/** Drag-lock distance threshold (in pixels). */
#define BUTTON_DRAGLOCK_THRESH 3
typedef enum uiButtonActivateType {
@@ -5244,8 +5246,8 @@ static bool ui_numedit_but_SLI(uiBut *but,
(but->softmax - but->softmin + but->a1);
}
else {
- const float offs = (BLI_rctf_size_y(&but->rect) / 2.0f);
- cursor_x_range = (BLI_rctf_size_x(&but->rect) - offs);
+ const float ofs = (BLI_rctf_size_y(&but->rect) / 2.0f);
+ cursor_x_range = (BLI_rctf_size_x(&but->rect) - ofs);
}
f = (mx_fl - data->dragstartx) / cursor_x_range + data->dragfstart;
@@ -7781,7 +7783,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if ((data->str &&
ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING)) ||
((abs(data->multi_data.drag_lock_x - event->x) > margin_x) &&
- /* just to be sure, check we're dragging more hoz then virt */
+ /* Just to be sure, check we're dragging more horizontally then vertically. */
abs(event->prevx - event->x) > abs(event->prevy - event->y))) {
if (data->multi_data.has_mbuts) {
ui_multibut_states_create(but, data);
@@ -9330,8 +9332,8 @@ static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEve
copy_v2_v2_int(keynav->event_xy, &event->x);
}
/**
- * Return true if keyinput isn't blocking mouse-motion,
- * or if the mouse-motion is enough to disable keyinput.
+ * Return true if key-input isn't blocking mouse-motion,
+ * or if the mouse-motion is enough to disable key-input.
*/
static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEvent *event)
{
@@ -10444,7 +10446,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
}
}
- if (event->type == block->pie_data.event && !is_click_style) {
+ if (event->type == block->pie_data.event_type && !is_click_style) {
if (event->val != KM_RELEASE) {
ui_handle_menu_button(C, event, menu);
@@ -10618,7 +10620,7 @@ static int ui_handle_menus_recursive(bContext *C,
/* root pie menus accept the key that spawned
* them as double click to improve responsiveness */
const bool do_recursion = (!(block->flag & UI_BLOCK_RADIAL) ||
- event->type != block->pie_data.event);
+ event->type != block->pie_data.event_type);
if (do_recursion) {
if (is_parent_inside == false) {
@@ -10911,7 +10913,7 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
/* set last pie event to allow chained pie spawning */
if (block->flag & UI_BLOCK_RADIAL) {
- win->last_pie_event = block->pie_data.event;
+ win->pie_event_type_last = block->pie_data.event_type;
reset_pie = true;
}
@@ -10954,7 +10956,7 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
wmWindow *win = CTX_wm_window(C);
if (win) {
- win->last_pie_event = EVENT_NONE;
+ win->pie_event_type_last = EVENT_NONE;
}
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index c39e2b3ff8a..1d4a44e0c76 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -424,8 +424,8 @@ struct PieMenuData {
float last_pos[2];
double duration_gesture;
int flags;
- /** initial event used to fire the pie menu, store here so we can query for release */
- int event;
+ /** Initial event used to fire the pie menu, store here so we can query for release */
+ short event_type;
float alphafac;
};
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index 81c627816b9..05aa139e055 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -122,26 +122,26 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co
* it is always assumed to be click style */
if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) {
pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
- pie->block_radial->pie_data.event = EVENT_NONE;
- win->lock_pie_event = EVENT_NONE;
+ pie->block_radial->pie_data.event_type = EVENT_NONE;
+ win->pie_event_type_lock = EVENT_NONE;
}
else {
- if (win->last_pie_event != EVENT_NONE) {
+ if (win->pie_event_type_last != EVENT_NONE) {
/* original pie key has been released, so don't propagate the event */
- if (win->lock_pie_event == EVENT_NONE) {
+ if (win->pie_event_type_lock == EVENT_NONE) {
event_type = EVENT_NONE;
pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
}
else {
- event_type = win->last_pie_event;
+ event_type = win->pie_event_type_last;
}
}
else {
event_type = event->type;
}
- pie->block_radial->pie_data.event = event_type;
- win->lock_pie_event = event_type;
+ pie->block_radial->pie_data.event_type = event_type;
+ win->pie_event_type_lock = event_type;
}
pie->layout = UI_block_layout(
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index e1f8f63dcbf..74668b2f3a3 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -642,6 +642,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
SPACE_MENU_NOP(SPACE_SCRIPT);
SPACE_MENU_NOP(SPACE_STATUSBAR);
SPACE_MENU_NOP(SPACE_TOPBAR);
+ SPACE_MENU_NOP(SPACE_SPREADSHEET);
}
}
for (int i = 0; i < idname_array_len; i++) {
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index c5e67e0334e..08895564a26 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -5485,7 +5485,7 @@ void uiTemplatePalette(uiLayout *layout,
}
}
-void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname)
+void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int icon)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -5500,7 +5500,7 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
UI_BTYPE_BUT,
"UI_OT_eyedropper_color",
WM_OP_INVOKE_DEFAULT,
- ICON_EYEDROPPER,
+ icon,
RNA_property_ui_name(prop),
0,
0,
@@ -5510,10 +5510,6 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
but->rnapoin = *ptr;
but->rnaprop = prop;
but->rnaindex = -1;
-
- PointerRNA *opptr = UI_but_operator_ptr_get(but);
- /* Important for crypto-matte operation. */
- RNA_boolean_set(opptr, "use_accumulate", false);
}
/** \} */
@@ -6383,9 +6379,9 @@ void uiTemplateList(uiLayout *layout,
}
if (glob) {
- /* About UI_BTYPE_GRIP drag-resize:
+ /* About #UI_BTYPE_GRIP drag-resize:
* We can't directly use results from a grip button, since we have a
- * rather complex behavior here (sizing by discrete steps and, overall, autosize feature).
+ * rather complex behavior here (sizing by discrete steps and, overall, auto-size feature).
* Since we *never* know whether we are grip-resizing or not
* (because there is no callback for when a button enters/leaves its "edit mode"),
* we use the fact that grip-controlled value (dyn_data->resize) is completely handled
@@ -6393,7 +6389,7 @@ void uiTemplateList(uiLayout *layout,
*
* It is only meaningful when we are not resizing,
* in which case this gives us the correct "init drag" value.
- * Note we cannot affect dyn_data->resize_prev here,
+ * Note we cannot affect `dyn_data->resize_prev here`,
* since this value is not controlled by the grip!
*/
dyn_data->resize = dyn_data->resize_prev +
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 0fa5999976b..0c6be7b1196 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -658,7 +658,7 @@ static int round_box_shadow_edges(
const float maxx = rect->xmax + step;
const float maxy = rect->ymax + step;
- /* mult */
+ /* Multiply. */
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
vec[a][0] = rad * cornervec[a][0];
vec[a][1] = rad * cornervec[a][1];
@@ -1180,7 +1180,7 @@ void UI_widgetbase_draw_cache_flush(void)
/* draw single */
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
GPU_batch_uniform_4fv_array(
- batch, "parameters", MAX_WIDGET_PARAMETERS, (float(*)[4])g_widget_base_batch.params);
+ batch, "parameters", MAX_WIDGET_PARAMETERS, (const float(*)[4])g_widget_base_batch.params);
GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
GPU_batch_draw(batch);
}
@@ -1819,7 +1819,7 @@ static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, cons
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr));
but->ofs = 0;
- /* First shorten num-buttons eg,
+ /* First shorten number-buttons eg,
* Translucency: 0.000
* becomes
* Trans: 0.000
@@ -3667,16 +3667,16 @@ static void widget_progressbar(
/* round corners */
const float value = but_progressbar->progress;
- const float offs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
+ const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
float w = value * BLI_rcti_size_x(&rect_prog);
/* Ensure minimum size. */
- w = MAX2(w, offs);
+ w = MAX2(w, ofs);
rect_bar.xmax = rect_bar.xmin + w;
- round_box_edges(&wtb, roundboxalign, &rect_prog, offs);
- round_box_edges(&wtb_bar, roundboxalign, &rect_bar, offs);
+ round_box_edges(&wtb, roundboxalign, &rect_prog, ofs);
+ round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs);
wtb.draw_outline = true;
widgetbase_draw(&wtb, wcol);
@@ -3733,9 +3733,9 @@ static void widget_numslider(
widget_init(&wtb1);
/* Backdrop first. */
- const float offs = wcol->roundness * BLI_rcti_size_y(rect);
- const float toffs = offs * 0.75f;
- round_box_edges(&wtb, roundboxalign, rect, offs);
+ const float ofs = wcol->roundness * BLI_rcti_size_y(rect);
+ const float toffs = ofs * 0.75f;
+ round_box_edges(&wtb, roundboxalign, rect, ofs);
wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
@@ -3768,13 +3768,13 @@ static void widget_numslider(
const float width = (float)BLI_rcti_size_x(rect);
factor_ui = factor * width;
- if (factor_ui <= offs) {
+ if (factor_ui <= ofs) {
/* Left part only. */
roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
- rect1.xmax = rect1.xmin + offs;
- factor_discard = factor_ui / offs;
+ rect1.xmax = rect1.xmin + ofs;
+ factor_discard = factor_ui / ofs;
}
- else if (factor_ui <= width - offs) {
+ else if (factor_ui <= width - ofs) {
/* Left part + middle part. */
roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
rect1.xmax = rect1.xmin + factor_ui;
@@ -3784,7 +3784,7 @@ static void widget_numslider(
factor_discard = factor;
}
- round_box_edges(&wtb1, roundboxalign_slider, &rect1, offs);
+ round_box_edges(&wtb1, roundboxalign_slider, &rect1, ofs);
wtb1.draw_outline = false;
widgetbase_set_uniform_discard_factor(&wtb1, factor_discard);
widgetbase_draw(&wtb1, wcol);
@@ -3801,7 +3801,7 @@ static void widget_numslider(
wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
- /* Add space at either side of the button so text aligns with numbuttons
+ /* Add space at either side of the button so text aligns with number-buttons
* (which have arrow icons). */
if (!(state & UI_STATE_TEXT_INPUT)) {
rect->xmax -= toffs;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 80e54f4f92f..afac254f542 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -160,6 +160,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case SPACE_STATUSBAR:
ts = &btheme->space_statusbar;
break;
+ case SPACE_SPREADSHEET:
+ ts = &btheme->space_spreadsheet;
+ break;
default:
ts = &btheme->space_view3d;
break;
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 1e66a86c8fd..bf20c1f6438 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -130,8 +130,8 @@ void CACHEFILE_OT_open(wmOperatorType *ot)
WM_operator_properties_filesel(ot,
FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
FILE_BLENDER,
- FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index d60d83850a5..18e231893d4 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -75,11 +75,8 @@ static Object *make_prim_init(bContext *C,
ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
- if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) {
- float scale_half[3];
- copy_v3_v3(scale_half, scale);
- mul_v3_fl(scale_half, 0.5f);
- rescale_m4(r_creation_data->mat, scale_half);
+ if (scale) {
+ rescale_m4(r_creation_data->mat, scale);
}
return obedit;
@@ -140,8 +137,8 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
"verts.out",
false,
"create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
- 1,
- 1,
+ 0,
+ 0,
RNA_float_get(op->ptr, "size") / 2.0f,
creation_data.mat,
calc_uvs)) {
@@ -534,9 +531,9 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
/* Note that if you use MESH_ADD_VERTS_MAXI for both x and y at the same time
* you will still reach impossible values (10^12 vertices or so...). */
RNA_def_int(
- ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000);
+ ot->srna, "x_subdivisions", 10, 1, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 1, 1000);
RNA_def_int(
- ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
+ ot->srna, "y_subdivisions", 10, 1, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 1, 1000);
ED_object_add_unit_props_size(ot);
ED_object_add_mesh_props(ot);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index b269a4f0514..0e3cc22d358 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -212,6 +212,7 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
nshapes,
use_self,
use_separate_all,
+ false,
true);
}
else {
@@ -375,8 +376,16 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
}
if (use_exact) {
- has_isect = BM_mesh_boolean(
- em->bm, em->looptris, em->tottri, test_fn, NULL, 2, use_self, true, boolean_operation);
+ has_isect = BM_mesh_boolean(em->bm,
+ em->looptris,
+ em->tottri,
+ test_fn,
+ NULL,
+ 2,
+ use_self,
+ true,
+ false,
+ boolean_operation);
}
else {
has_isect = BM_mesh_intersect(em->bm,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 1f894ec0f1d..b5ec3f388a0 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -966,7 +966,7 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
float planes[4][4];
planes_from_projmat(
- (float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL);
+ (const float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL);
/* ray-cast all planes */
{
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 03b4cda2005..33797573f2b 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -97,7 +97,9 @@ static float edbm_rip_linedist(
}
#endif
-/* calculaters a point along the loop tangent which can be used to measure against edges */
+/**
+ * Calculates a point along the loop tangent which can be used to measure against edges.
+ */
static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
{
BM_loop_calc_face_tangent(l, l_mid_co);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 903e50bf668..35608a4abde 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -1524,7 +1524,13 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
else {
for (edindex = 0; edindex < totedgesel; edindex += 1) {
eed = edarray[edindex];
- walker_select(em, BMW_EDGELOOP, eed, true);
+ bool non_manifold = BM_edge_face_count_is_over(eed, 2);
+ if (non_manifold) {
+ walker_select(em, BMW_EDGELOOP_NONMANIFOLD, eed, true);
+ }
+ else {
+ walker_select(em, BMW_EDGELOOP, eed, true);
+ }
}
EDBM_selectmode_flush(em);
}
@@ -1585,6 +1591,7 @@ static void mouse_mesh_loop_edge(
BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle)
{
bool edge_boundary = false;
+ bool non_manifold = BM_edge_face_count_is_over(eed, 2);
/* Cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY. */
if (select_cycle && BM_edge_is_boundary(eed)) {
@@ -1610,6 +1617,9 @@ static void mouse_mesh_loop_edge(
if (edge_boundary) {
walker_select(em, BMW_EDGEBOUNDARY, eed, select);
}
+ else if (non_manifold) {
+ walker_select(em, BMW_EDGELOOP_NONMANIFOLD, eed, select);
+ }
else {
walker_select(em, BMW_EDGELOOP, eed, select);
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 43e0ab97f5d..8bb557509e0 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -1967,9 +1967,9 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
edbm_duplicate_exec(C, op);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
return OPERATOR_FINISHED;
}
@@ -4172,15 +4172,7 @@ static Base *mesh_separate_tagged(
}));
BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
- CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
- CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
- CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
- CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
-
- CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT);
- CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE);
- CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP);
- CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE);
+ BM_mesh_copy_init_customdata(bm_new, bm_old, &bm_mesh_allocsize_default);
/* Take into account user preferences for duplicating actions. */
const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT);
@@ -7754,7 +7746,7 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
/** \} */
-#ifdef WITH_FREESTYLE
+#if defined(WITH_FREESTYLE)
/* -------------------------------------------------------------------- */
/** \name Mark Edge (Freestyle) Operator
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 21feddfb886..763bdf04d83 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -267,7 +267,7 @@ void MESH_OT_paint_mask_slice(struct wmOperatorType *ot);
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
-#ifdef WITH_FREESTYLE
+#if defined(WITH_FREESTYLE)
void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
#endif
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 27d73497b49..34e9a3f45a5 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -130,7 +130,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_loop_multi_select);
WM_operatortype_append(MESH_OT_mark_seam);
WM_operatortype_append(MESH_OT_mark_sharp);
-#ifdef WITH_FREESTYLE
+#if defined(WITH_FREESTYLE)
WM_operatortype_append(MESH_OT_mark_freestyle_edge);
#endif
WM_operatortype_append(MESH_OT_vertices_smooth);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index dc941f12eba..e4527740164 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -31,6 +31,7 @@
#include "DNA_camera_types.h"
#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_light_types.h"
@@ -68,6 +69,7 @@
#include "BKE_geometry_set.h"
#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_hair.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -1305,7 +1307,7 @@ static bool object_gpencil_add_poll(bContext *C)
static int object_gpencil_add_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C), *ob_orig = ob;
bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL;
const int type = RNA_enum_get(op->ptr, "type");
@@ -1333,6 +1335,11 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
ob_name = "Stroke";
break;
}
+ case GP_LRT_OBJECT:
+ case GP_LRT_COLLECTION: {
+ ob_name = "Line Art";
+ break;
+ }
default: {
break;
}
@@ -1373,6 +1380,46 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
ED_gpencil_create_monkey(C, ob, mat);
break;
}
+ case GP_LRT_SCENE:
+ case GP_LRT_COLLECTION:
+ case GP_LRT_OBJECT: {
+ float radius = RNA_float_get(op->ptr, "radius");
+ float mat[4][4];
+
+ ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ mul_v3_fl(mat[0], radius);
+ mul_v3_fl(mat[1], radius);
+ mul_v3_fl(mat[2], radius);
+
+ ED_gpencil_create_lineart(C, ob);
+
+ gpd = ob->data;
+
+ /* Add Line Art modifier */
+ LineartGpencilModifierData *md = (LineartGpencilModifierData *)BKE_gpencil_modifier_new(
+ eGpencilModifierType_Lineart);
+ BLI_addtail(&ob->greasepencil_modifiers, md);
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, (GpencilModifierData *)md);
+
+ if (type == GP_LRT_COLLECTION) {
+ md->source_type = LRT_SOURCE_COLLECTION;
+ md->source_collection = CTX_data_collection(C);
+ }
+ else if (type == GP_LRT_OBJECT) {
+ md->source_type = LRT_SOURCE_OBJECT;
+ md->source_object = ob_orig;
+ }
+ else {
+ /* Whole scene. */
+ md->source_type = LRT_SOURCE_SCENE;
+ }
+ /* Only created one layer and one material. */
+ strcpy(md->target_layer, ((bGPDlayer *)gpd->layers.first)->info);
+ md->target_material = BKE_gpencil_material(ob, 1);
+
+ /* Stroke object is drawn in front of meshes by default. */
+ ob->dtx |= OB_DRAW_IN_FRONT;
+ }
case GP_EMPTY:
/* do nothing */
break;
@@ -1393,6 +1440,41 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static const EnumPropertyItem *object_gpencil_add_options(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ const EnumPropertyItem *item_ref = rna_enum_object_gpencil_type_items;
+ int totitem = 0;
+ int i = 0;
+ int orig_count = RNA_enum_items_count(item_ref);
+
+ /* Default types. */
+ for (i = 0; i < orig_count; i++) {
+ if (item_ref[i].value == GP_LRT_OBJECT || item_ref[i].value == GP_LRT_COLLECTION ||
+ item_ref[i].value == GP_LRT_SCENE) {
+ if (item_ref[i].value == GP_LRT_SCENE) {
+ /* separator before line art types */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+ else if (item_ref[i].value == GP_LRT_OBJECT) {
+ Object *ob = CTX_data_active_object(C);
+ if (!ob || ob->type != OB_MESH) {
+ continue;
+ }
+ }
+ }
+ RNA_enum_item_add(&item, &totitem, &item_ref[i]);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
void OBJECT_OT_gpencil_add(wmOperatorType *ot)
{
/* identifiers */
@@ -1413,6 +1495,7 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, false);
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
+ RNA_def_enum_funcs(ot->prop, object_gpencil_add_options);
}
/** \} */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 9618774eea8..a5cad4e087c 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -572,7 +572,7 @@ static int multiresbake_image_exec(bContext *C, wmOperator *op)
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
/* add modal handler for ESC */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 9ec0c625f71..d64769567f7 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -450,8 +450,9 @@ static bool bake_object_check(ViewLayer *view_layer,
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+ const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors);
MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
- if (mcol == NULL && mloopcol == NULL) {
+ if (mloopcol == NULL && !mcol_valid) {
BKE_reportf(reports,
RPT_ERROR,
"No vertex colors layer found in the object \"%s\"",
@@ -933,8 +934,9 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+ const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors);
MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
- if (mcol == NULL && mloopcol == NULL) {
+ if (mloopcol == NULL && !mcol_valid) {
BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to");
return false;
}
@@ -1043,6 +1045,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob,
{
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+ const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors);
MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
const int num_channels = targets->num_channels;
const float *result = targets->result;
@@ -1052,7 +1055,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob,
BLI_assert(me->totloop == me_split->totloop);
UNUSED_VARS_NDEBUG(me_split);
- if (mcol) {
+ if (mcol_valid) {
const int totvert = me->totvert;
const int totloop = me->totloop;
@@ -1897,7 +1900,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
/* add modal handler for ESC */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index da14d4ef52a..c774bc9f9cc 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1330,9 +1330,9 @@ static int object_clear_paths_exec(bContext *C, wmOperator *op)
}
/* operator callback/wrapper */
-static int object_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+static int object_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
+ if ((event->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
RNA_boolean_set(op->ptr, "only_selected", true);
}
return object_clear_paths_exec(C, op);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 57676cf5c76..71bea6bf9e3 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -37,6 +37,8 @@
#include "object_intern.h"
+#include "MOD_gpencil_lineart.h"
+
/* ************************** registration **********************************/
void ED_operatortypes_object(void)
@@ -154,6 +156,9 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy);
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy_to_selected);
+ /* grease pencil line art */
+ WM_operatortypes_lineart();
+
/* Shader FX. */
WM_operatortype_append(OBJECT_OT_shaderfx_add);
WM_operatortype_append(OBJECT_OT_shaderfx_remove);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 5a2ef1c6556..0aa739c2fc8 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -893,10 +893,10 @@ bool ED_object_parent_set(ReportList *reports,
reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror);
}
else if (partype == PAR_ARMATURE_AUTO) {
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
ED_object_vgroup_calc_from_armature(
reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
}
/* get corrected inverse */
ob->partype = PAROBJECT;
@@ -912,9 +912,9 @@ bool ED_object_parent_set(ReportList *reports,
ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME);
}
else if (ELEM(partype, PAR_ARMATURE_AUTO, PAR_ARMATURE_ENVELOPE)) {
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
}
/* get corrected inverse */
ob->partype = PAROBJECT;
@@ -1756,7 +1756,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C));
WM_event_add_notifier(C, NC_OBJECT, NULL);
@@ -2712,7 +2712,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
DEG_id_tag_update(&base->object->id, ID_RECALC_TRANSFORM);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index b525d8a373e..1f59e361526 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -938,7 +938,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
/* handle UI stuff */
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
/* flush sculpt and editmode changes */
ED_editors_flush_edits_ex(bmain, true, false);
@@ -1058,7 +1058,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
/* we set G.is_rendering here already instead of only in the job, this ensure
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 9811b7caa38..1b7209b164b 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -1342,7 +1342,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
* already there. Very expensive for large images. Need to find a way to
* only get existing ibuf */
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || ibuf->rect == NULL) {
+ if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 32d4abcabd4..b4cac58db1f 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -1074,6 +1074,11 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ if (view_layer->active_aov == NULL) {
+ return OPERATOR_FINISHED;
+ }
+
BKE_view_layer_remove_aov(view_layer, view_layer->active_aov);
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
@@ -1224,7 +1229,7 @@ static int light_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *U
WM_jobs_start(wm, wm_job);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
return OPERATOR_RUNNING_MODAL;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 8a53154cc85..797c3bcf132 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -5540,10 +5540,6 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
/* Screen Editing ------------------------------------------------ */
WM_keymap_ensure(keyconf, "Screen Editing", 0, 0);
- /* Header Editing ------------------------------------------------ */
- /* note: this is only used when the cursor is inside the header */
- WM_keymap_ensure(keyconf, "Header", 0, 0);
-
/* Screen General ------------------------------------------------ */
WM_keymap_ensure(keyconf, "Screen", 0, 0);
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index fff172c0707..3b668a1bd4c 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
sculpt_filter_mesh.c
sculpt_geodesic.c
sculpt_mask_expand.c
+ sculpt_mask_init.c
sculpt_multiplane_scrape.c
sculpt_paint_color.c
sculpt_pose.c
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 26e2bcc42cf..7671f69ee05 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -131,8 +131,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
float prevmask = *vi.mask;
mask_flood_fill_set_elem(vi.mask, mode, value);
if (prevmask != *vi.mask) {
@@ -757,8 +756,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
bool any_updated = false;
- BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id);
any_updated = true;
@@ -832,8 +830,7 @@ static void mask_gesture_apply_task_cb(void *__restrict userdata,
bool any_masked = false;
bool redraw = false;
- BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
float prevmask = *vd.mask;
if (!any_masked) {
@@ -1292,7 +1289,8 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
BLI_assert(false);
break;
}
- BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, boolean_mode);
+ BM_mesh_boolean(
+ bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, false, boolean_mode);
}
MEM_freeN(looptris);
@@ -1414,8 +1412,7 @@ static void project_line_gesture_apply_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(sgcontext->vc.obact, node, SCULPT_UNDO_COORDS);
- BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if (!sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
continue;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index f45c244f675..fc52f6fea7c 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1841,8 +1841,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
@@ -1938,8 +1937,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
@@ -2045,8 +2043,7 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* Note: grids are 1:1 with corners (aka loops).
@@ -2114,8 +2111,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) :
@@ -2810,8 +2806,7 @@ static void do_vpaint_brush_calc_average_color_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
@@ -2880,8 +2875,7 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* Note: Grids are 1:1 with corners (aka loops).
@@ -2979,8 +2973,7 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
@@ -3103,8 +3096,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
/* For each vertex */
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 631327ddfe8..964e5bdaa90 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -76,11 +76,6 @@
#include "IMB_colormanagement.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
-
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
@@ -89,7 +84,6 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
-#include "ED_space_api.h"
#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -976,8 +970,7 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
NearestVertexTLSData *nvtd = tls->userdata_chunk;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
@@ -1494,8 +1487,7 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
SCULPT_orig_vert_data_unode_init(&orig_data, data->ob, unode);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
@@ -2056,8 +2048,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
}
}
else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float co[3];
/* For bm_vert only. */
@@ -2928,8 +2919,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3001,8 +2991,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3078,8 +3067,7 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3144,8 +3132,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3225,8 +3212,7 @@ static void do_displacement_smear_store_prev_disp_task_cb_ex(
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
SCULPT_vertex_co_get(ss, vd.index),
ss->cache->limit_surface_co[vd.index]);
@@ -3289,8 +3275,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3368,8 +3353,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@@ -3451,8 +3435,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@@ -3609,8 +3592,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@@ -3776,8 +3758,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3894,8 +3875,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
copy_v3_v3(x_object_space, stroke_xz[0]);
copy_v3_v3(z_object_space, stroke_xz[1]);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -4009,8 +3989,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
@@ -4111,8 +4090,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
BKE_kelvinlet_init_params(
&params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float final_disp[3];
switch (brush->elastic_deform_type) {
@@ -4342,8 +4320,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -4422,8 +4399,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
KelvinletParams params;
BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -4560,8 +4536,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
@@ -4634,8 +4609,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
@@ -4707,8 +4681,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
@@ -4822,8 +4795,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -4928,8 +4900,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -5035,8 +5006,7 @@ static void calc_clay_surface_task_cb(void *__restrict userdata,
return;
}
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -5086,8 +5056,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -5206,8 +5175,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
continue;
}
@@ -5360,8 +5328,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -5459,8 +5426,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -5574,8 +5540,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
/* Tilted plane (front part of the brush). */
plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -5730,8 +5695,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -6242,8 +6206,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float val[3];
if (use_orco) {
@@ -6338,8 +6301,7 @@ static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
sculpt_flush_pbvhvert_deform(ob, &vd);
if (!vertCos) {
@@ -8923,8 +8885,7 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
NearestVertexFakeNeighborTLSData *nvtd = tls->userdata_chunk;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index);
if (vd_topology_id != nvtd->current_topology_id &&
ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) {
@@ -9194,8 +9155,7 @@ static void do_mask_by_color_contiguous_update_nodes_cb(
const bool preserve_mask = data->mask_by_color_preserve_mask;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
const float current_mask = *vd.mask;
const float new_mask = data->mask_by_color_floodfill[vd.index];
*vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
@@ -9301,8 +9261,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata,
const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
const float current_mask = *vd.mask;
const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
*vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
@@ -9433,335 +9392,6 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
1.0f);
}
-/* -------------------------------------------------------------------- */
-/** \name Dyntopo Detail Size Edit Operator
- * \{ */
-
-/* Defines how much the mouse movement will modify the detail size value. */
-#define DETAIL_SIZE_DELTA_SPEED 0.08f
-#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
-
-typedef struct DyntopoDetailSizeEditCustomData {
- void *draw_handle;
- Object *active_object;
-
- float init_mval[2];
- float accurate_mval[2];
-
- float outline_col[4];
-
- bool accurate_mode;
- bool sample_mode;
-
- float init_detail_size;
- float accurate_detail_size;
- float detail_size;
- float radius;
-
- float preview_tri[3][3];
- float gizmo_mat[4][4];
-} DyntopoDetailSizeEditCustomData;
-
-static void dyntopo_detail_size_parallel_lines_draw(uint pos3d,
- DyntopoDetailSizeEditCustomData *cd,
- const float start_co[3],
- const float end_co[3],
- bool flip,
- const float angle)
-{
- float object_space_constant_detail = 1.0f /
- (cd->detail_size * mat4_to_scale(cd->active_object->obmat));
-
- /* The constant detail represents the maximum edge length allowed before subdividing it. If the
- * triangle grid preview is created with this value it will represent an ideal mesh density where
- * all edges have the exact maximum length, which never happens in practice. As the minimum edge
- * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average
- * between max and min edge length so the preview is more accurate. */
- object_space_constant_detail *= 0.7f;
-
- const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]);
- const int tot_lines = (int)(total_len / object_space_constant_detail) + 1;
- const float tot_lines_fl = total_len / object_space_constant_detail;
- float spacing_disp[3];
- sub_v3_v3v3(spacing_disp, end_co, start_co);
- normalize_v3(spacing_disp);
-
- float line_disp[3];
- rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle));
- mul_v3_fl(spacing_disp, total_len / tot_lines_fl);
-
- immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2);
- for (int i = 0; i < tot_lines; i++) {
- float line_length;
- if (flip) {
- line_length = total_len * ((float)i / (float)tot_lines_fl);
- }
- else {
- line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl));
- }
- float line_start[3];
- copy_v3_v3(line_start, start_co);
- madd_v3_v3v3fl(line_start, line_start, spacing_disp, i);
- float line_end[3];
- madd_v3_v3v3fl(line_end, line_start, line_disp, line_length);
- immVertex3fv(pos3d, line_start);
- immVertex3fv(pos3d, line_end);
- }
- immEnd();
-}
-
-static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C),
- ARegion *UNUSED(ar),
- void *arg)
-{
- DyntopoDetailSizeEditCustomData *cd = arg;
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
-
- uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- GPU_matrix_push();
- GPU_matrix_mul(cd->gizmo_mat);
-
- /* Draw Cursor */
- immUniformColor4fv(cd->outline_col);
- GPU_line_width(3.0f);
-
- imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80);
-
- /* Draw Triangle. */
- immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
- immBegin(GPU_PRIM_LINES, 6);
- immVertex3fv(pos3d, cd->preview_tri[0]);
- immVertex3fv(pos3d, cd->preview_tri[1]);
-
- immVertex3fv(pos3d, cd->preview_tri[1]);
- immVertex3fv(pos3d, cd->preview_tri[2]);
-
- immVertex3fv(pos3d, cd->preview_tri[2]);
- immVertex3fv(pos3d, cd->preview_tri[0]);
- immEnd();
-
- /* Draw Grid */
- GPU_line_width(1.0f);
- dyntopo_detail_size_parallel_lines_draw(
- pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f);
- dyntopo_detail_size_parallel_lines_draw(
- pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f);
- dyntopo_detail_size_parallel_lines_draw(
- pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f);
-
- immUnbindProgram();
- GPU_matrix_pop();
- GPU_blend(GPU_BLEND_NONE);
- GPU_line_smooth(false);
-}
-
-static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
-{
- Object *active_object = CTX_data_active_object(C);
- SculptSession *ss = active_object->sculpt;
- ARegion *region = CTX_wm_region(C);
- DyntopoDetailSizeEditCustomData *cd = op->customdata;
- ED_region_draw_cb_exit(region->type, cd->draw_handle);
- ss->draw_faded_cursor = false;
- MEM_freeN(op->customdata);
- ED_workspace_status_text(C, NULL);
-}
-
-static void dyntopo_detail_size_sample_from_surface(Object *ob,
- DyntopoDetailSizeEditCustomData *cd)
-{
- SculptSession *ss = ob->sculpt;
- const int active_vertex = SCULPT_active_vertex_get(ss);
-
- float len_accum = 0;
- int num_neighbors = 0;
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
- len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
- SCULPT_vertex_co_get(ss, ni.index));
- num_neighbors++;
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- if (num_neighbors > 0) {
- const float avg_edge_len = len_accum / num_neighbors;
- /* Use 0.7 as the average of min and max dyntopo edge length. */
- const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat));
- cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f);
- }
-}
-
-static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd,
- const wmEvent *event)
-{
- const float mval[2] = {event->mval[0], event->mval[1]};
-
- float detail_size_delta;
- if (cd->accurate_mode) {
- detail_size_delta = mval[0] - cd->accurate_mval[0];
- cd->detail_size = cd->accurate_detail_size +
- detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED;
- }
- else {
- detail_size_delta = mval[0] - cd->init_mval[0];
- cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED;
- }
-
- if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
- cd->accurate_mode = true;
- copy_v2_v2(cd->accurate_mval, mval);
- cd->accurate_detail_size = cd->detail_size;
- }
- if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
- cd->accurate_mode = false;
- cd->accurate_detail_size = 0.0f;
- }
-
- cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f);
-}
-
-static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *active_object = CTX_data_active_object(C);
- SculptSession *ss = active_object->sculpt;
- ARegion *region = CTX_wm_region(C);
- DyntopoDetailSizeEditCustomData *cd = op->customdata;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- /* Cancel modal operator */
- if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
- (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
- dyntopo_detail_size_edit_cancel(C, op);
- ED_region_tag_redraw(region);
- return OPERATOR_FINISHED;
- }
-
- /* Finish modal operator */
- if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
- (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
- (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
- ED_region_draw_cb_exit(region->type, cd->draw_handle);
- sd->constant_detail = cd->detail_size;
- ss->draw_faded_cursor = false;
- MEM_freeN(op->customdata);
- ED_region_tag_redraw(region);
- ED_workspace_status_text(C, NULL);
- return OPERATOR_FINISHED;
- }
-
- ED_region_tag_redraw(region);
-
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
- cd->sample_mode = true;
- }
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
- cd->sample_mode = false;
- }
-
- /* Sample mode sets the detail size sampling the average edge length under the surface. */
- if (cd->sample_mode) {
- dyntopo_detail_size_sample_from_surface(active_object, cd);
- return OPERATOR_RUNNING_MODAL;
- }
- /* Regular mode, changes the detail size by moving the cursor. */
- dyntopo_detail_size_update_from_mouse_delta(cd, event);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- Object *active_object = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData),
- "Dyntopo Detail Size Edit OP Custom Data");
-
- /* Initial operator Custom Data setup. */
- cd->draw_handle = ED_region_draw_cb_activate(
- region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
- cd->active_object = active_object;
- cd->init_mval[0] = event->mval[0];
- cd->init_mval[1] = event->mval[1];
- cd->detail_size = sd->constant_detail;
- cd->init_detail_size = sd->constant_detail;
- copy_v4_v4(cd->outline_col, brush->add_col);
- op->customdata = cd;
-
- SculptSession *ss = active_object->sculpt;
- cd->radius = ss->cursor_radius;
-
- /* Generates the matrix to position the gizmo in the surface of the mesh using the same location
- * and orientation as the brush cursor. */
- float cursor_trans[4][4], cursor_rot[4][4];
- const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float quat[4];
- copy_m4_m4(cursor_trans, active_object->obmat);
- translate_m4(
- cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]);
-
- float cursor_normal[3];
- if (!is_zero_v3(ss->cursor_sampled_normal)) {
- copy_v3_v3(cursor_normal, ss->cursor_sampled_normal);
- }
- else {
- copy_v3_v3(cursor_normal, ss->cursor_normal);
- }
-
- rotation_between_vecs_to_quat(quat, z_axis, cursor_normal);
- quat_to_mat4(cursor_rot, quat);
- copy_m4_m4(cd->gizmo_mat, cursor_trans);
- mul_m4_m4_post(cd->gizmo_mat, cursor_rot);
-
- /* Initialize the position of the triangle vertices. */
- const float y_axis[3] = {0.0f, cd->radius, 0.0f};
- for (int i = 0; i < 3; i++) {
- zero_v3(cd->preview_tri[i]);
- rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i));
- }
-
- SCULPT_vertex_random_access_ensure(ss);
-
- WM_event_add_modal_handler(C, op);
- ED_region_tag_redraw(region);
-
- ss->draw_faded_cursor = true;
-
- const char *status_str = TIP_(
- "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel");
- ED_workspace_status_text(C, status_str);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static bool dyntopo_detail_size_edit_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- return SCULPT_mode_poll(C) && ob->sculpt->bm && (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT);
-}
-
-static void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Edit Dyntopo Detail Size";
- ot->description = "Modify the constant detail size of dyntopo interactively";
- ot->idname = "SCULPT_OT_dyntopo_detail_size_edit";
-
- /* api callbacks */
- ot->poll = dyntopo_detail_size_edit_poll;
- ot->invoke = dyntopo_detail_size_edit_invoke;
- ot->modal = dyntopo_detail_size_edit_modal;
- ot->cancel = dyntopo_detail_size_edit_cancel;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
void ED_operatortypes_sculpt(void)
{
WM_operatortype_append(SCULPT_OT_brush_stroke);
@@ -9796,6 +9426,7 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_color_filter);
WM_operatortype_append(SCULPT_OT_mask_by_color);
WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
+ WM_operatortype_append(SCULPT_OT_mask_init);
WM_operatortype_append(SCULPT_OT_expand);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index f1fb402ae41..37678ec276a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -589,6 +589,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
+ continue;
}
sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
@@ -666,8 +667,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
}
const float angle = angle_factor * M_PI;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
continue;
}
@@ -715,8 +715,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
continue;
}
@@ -762,8 +761,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
continue;
}
@@ -809,8 +807,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
continue;
}
@@ -861,8 +858,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
}
const float angle = angle_factor * M_PI;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
continue;
}
@@ -908,8 +904,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
continue;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 16d10f6d6bb..a53a2126af4 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -377,8 +377,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
data->cloth_sim_radius * data->cloth_sim_radius :
FLT_MAX;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
const float len_squared = len_squared_v3v3(vd.co, data->cloth_sim_initial_location);
if (len_squared < cloth_sim_radius_squared) {
@@ -518,8 +517,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
madd_v3_v3fl(gravity, ss->cache->gravity_direction, -data->sd->gravity_factor);
}
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float force[3];
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
@@ -783,8 +781,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
const float sim_factor =
@@ -1449,8 +1446,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float fade = vd.mask ? *vd.mask : 0.0f;
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
fade = 1.0f - fade;
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index ddf7ba1e412..188bb0a88eb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -37,10 +37,17 @@
#include "DEG_depsgraph.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_space_api.h"
#include "ED_view3d.h"
#include "sculpt_intern.h"
@@ -118,7 +125,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
MEM_SAFE_FREE(nodes);
SCULPT_undo_push_end();
- /* Force rebuild of pbvh for better BB placement. */
+ /* Force rebuild of PBVH for better BB placement. */
SCULPT_pbvh_clear(ob);
/* Redraw. */
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -359,8 +366,12 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
/* Dynamic-topology detail size.
*
- * This should be improved further, perhaps by showing a triangle
- * grid rather than brush alpha. */
+ * Currently, there are two operators editing the detail size:
+ * - SCULPT_OT_set_detail_size uses radial control for all methods
+ * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
+ * resolution (for constant detail method, falls back to radial control for the remaining methods).
+ */
+
static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
{
char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
@@ -368,7 +379,7 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
MEM_freeN(path);
}
-static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+static void sculpt_detail_size_set_radial_control(bContext *C)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -394,6 +405,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
+}
+
+static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ sculpt_detail_size_set_radial_control(C);
return OPERATOR_FINISHED;
}
@@ -412,3 +428,334 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* -------------------------------------------------------------------- */
+/** \name Dyntopo Detail Size Edit Operator
+ * \{ */
+
+/* Defines how much the mouse movement will modify the detail size value. */
+#define DETAIL_SIZE_DELTA_SPEED 0.08f
+#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
+
+typedef struct DyntopoDetailSizeEditCustomData {
+ void *draw_handle;
+ Object *active_object;
+
+ float init_mval[2];
+ float accurate_mval[2];
+
+ float outline_col[4];
+
+ bool accurate_mode;
+ bool sample_mode;
+
+ float init_detail_size;
+ float accurate_detail_size;
+ float detail_size;
+ float radius;
+
+ float preview_tri[3][3];
+ float gizmo_mat[4][4];
+} DyntopoDetailSizeEditCustomData;
+
+static void dyntopo_detail_size_parallel_lines_draw(uint pos3d,
+ DyntopoDetailSizeEditCustomData *cd,
+ const float start_co[3],
+ const float end_co[3],
+ bool flip,
+ const float angle)
+{
+ float object_space_constant_detail = 1.0f /
+ (cd->detail_size * mat4_to_scale(cd->active_object->obmat));
+
+ /* The constant detail represents the maximum edge length allowed before subdividing it. If the
+ * triangle grid preview is created with this value it will represent an ideal mesh density where
+ * all edges have the exact maximum length, which never happens in practice. As the minimum edge
+ * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average
+ * between max and min edge length so the preview is more accurate. */
+ object_space_constant_detail *= 0.7f;
+
+ const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]);
+ const int tot_lines = (int)(total_len / object_space_constant_detail) + 1;
+ const float tot_lines_fl = total_len / object_space_constant_detail;
+ float spacing_disp[3];
+ sub_v3_v3v3(spacing_disp, end_co, start_co);
+ normalize_v3(spacing_disp);
+
+ float line_disp[3];
+ rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle));
+ mul_v3_fl(spacing_disp, total_len / tot_lines_fl);
+
+ immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2);
+ for (int i = 0; i < tot_lines; i++) {
+ float line_length;
+ if (flip) {
+ line_length = total_len * ((float)i / (float)tot_lines_fl);
+ }
+ else {
+ line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl));
+ }
+ float line_start[3];
+ copy_v3_v3(line_start, start_co);
+ madd_v3_v3v3fl(line_start, line_start, spacing_disp, i);
+ float line_end[3];
+ madd_v3_v3v3fl(line_end, line_start, line_disp, line_length);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+}
+
+static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C),
+ ARegion *UNUSED(ar),
+ void *arg)
+{
+ DyntopoDetailSizeEditCustomData *cd = arg;
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_line_smooth(true);
+
+ uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->gizmo_mat);
+
+ /* Draw Cursor */
+ immUniformColor4fv(cd->outline_col);
+ GPU_line_width(3.0f);
+
+ imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80);
+
+ /* Draw Triangle. */
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
+ immBegin(GPU_PRIM_LINES, 6);
+ immVertex3fv(pos3d, cd->preview_tri[0]);
+ immVertex3fv(pos3d, cd->preview_tri[1]);
+
+ immVertex3fv(pos3d, cd->preview_tri[1]);
+ immVertex3fv(pos3d, cd->preview_tri[2]);
+
+ immVertex3fv(pos3d, cd->preview_tri[2]);
+ immVertex3fv(pos3d, cd->preview_tri[0]);
+ immEnd();
+
+ /* Draw Grid */
+ GPU_line_width(1.0f);
+ dyntopo_detail_size_parallel_lines_draw(
+ pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f);
+ dyntopo_detail_size_parallel_lines_draw(
+ pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f);
+ dyntopo_detail_size_parallel_lines_draw(
+ pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f);
+
+ immUnbindProgram();
+ GPU_matrix_pop();
+ GPU_blend(GPU_BLEND_NONE);
+ GPU_line_smooth(false);
+}
+
+static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
+{
+ Object *active_object = CTX_data_active_object(C);
+ SculptSession *ss = active_object->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ DyntopoDetailSizeEditCustomData *cd = op->customdata;
+ ED_region_draw_cb_exit(region->type, cd->draw_handle);
+ ss->draw_faded_cursor = false;
+ MEM_freeN(op->customdata);
+ ED_workspace_status_text(C, NULL);
+}
+
+static void dyntopo_detail_size_sample_from_surface(Object *ob,
+ DyntopoDetailSizeEditCustomData *cd)
+{
+ SculptSession *ss = ob->sculpt;
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+
+ float len_accum = 0;
+ int num_neighbors = 0;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
+ len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
+ SCULPT_vertex_co_get(ss, ni.index));
+ num_neighbors++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (num_neighbors > 0) {
+ const float avg_edge_len = len_accum / num_neighbors;
+ /* Use 0.7 as the average of min and max dyntopo edge length. */
+ const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat));
+ cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f);
+ }
+}
+
+static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd,
+ const wmEvent *event)
+{
+ const float mval[2] = {event->mval[0], event->mval[1]};
+
+ float detail_size_delta;
+ if (cd->accurate_mode) {
+ detail_size_delta = mval[0] - cd->accurate_mval[0];
+ cd->detail_size = cd->accurate_detail_size +
+ detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED;
+ }
+ else {
+ detail_size_delta = mval[0] - cd->init_mval[0];
+ cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED;
+ }
+
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
+ cd->accurate_mode = true;
+ copy_v2_v2(cd->accurate_mval, mval);
+ cd->accurate_detail_size = cd->detail_size;
+ }
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
+ cd->accurate_mode = false;
+ cd->accurate_detail_size = 0.0f;
+ }
+
+ cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f);
+}
+
+static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *active_object = CTX_data_active_object(C);
+ SculptSession *ss = active_object->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ DyntopoDetailSizeEditCustomData *cd = op->customdata;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ /* Cancel modal operator */
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ dyntopo_detail_size_edit_cancel(C, op);
+ ED_region_tag_redraw(region);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Finish modal operator */
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+ ED_region_draw_cb_exit(region->type, cd->draw_handle);
+ sd->constant_detail = cd->detail_size;
+ ss->draw_faded_cursor = false;
+ MEM_freeN(op->customdata);
+ ED_region_tag_redraw(region);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ ED_region_tag_redraw(region);
+
+ if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
+ cd->sample_mode = true;
+ }
+ if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
+ cd->sample_mode = false;
+ }
+
+ /* Sample mode sets the detail size sampling the average edge length under the surface. */
+ if (cd->sample_mode) {
+ dyntopo_detail_size_sample_from_surface(active_object, cd);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ /* Regular mode, changes the detail size by moving the cursor. */
+ dyntopo_detail_size_update_from_mouse_delta(cd, event);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ /* Fallback to radial control for modes other than SCULPT_DYNTOPO_DETAIL_CONSTANT [same as in
+ * SCULPT_OT_set_detail_size]. */
+ if (!(sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL))) {
+ sculpt_detail_size_set_radial_control(C);
+
+ return OPERATOR_FINISHED;
+ }
+
+ /* Special method for SCULPT_DYNTOPO_DETAIL_CONSTANT. */
+ ARegion *region = CTX_wm_region(C);
+ Object *active_object = CTX_data_active_object(C);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData),
+ "Dyntopo Detail Size Edit OP Custom Data");
+
+ /* Initial operator Custom Data setup. */
+ cd->draw_handle = ED_region_draw_cb_activate(
+ region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
+ cd->active_object = active_object;
+ cd->init_mval[0] = event->mval[0];
+ cd->init_mval[1] = event->mval[1];
+ cd->detail_size = sd->constant_detail;
+ cd->init_detail_size = sd->constant_detail;
+ copy_v4_v4(cd->outline_col, brush->add_col);
+ op->customdata = cd;
+
+ SculptSession *ss = active_object->sculpt;
+ cd->radius = ss->cursor_radius;
+
+ /* Generates the matrix to position the gizmo in the surface of the mesh using the same location
+ * and orientation as the brush cursor. */
+ float cursor_trans[4][4], cursor_rot[4][4];
+ const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+ copy_m4_m4(cursor_trans, active_object->obmat);
+ translate_m4(
+ cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]);
+
+ float cursor_normal[3];
+ if (!is_zero_v3(ss->cursor_sampled_normal)) {
+ copy_v3_v3(cursor_normal, ss->cursor_sampled_normal);
+ }
+ else {
+ copy_v3_v3(cursor_normal, ss->cursor_normal);
+ }
+
+ rotation_between_vecs_to_quat(quat, z_axis, cursor_normal);
+ quat_to_mat4(cursor_rot, quat);
+ copy_m4_m4(cd->gizmo_mat, cursor_trans);
+ mul_m4_m4_post(cd->gizmo_mat, cursor_rot);
+
+ /* Initialize the position of the triangle vertices. */
+ const float y_axis[3] = {0.0f, cd->radius, 0.0f};
+ for (int i = 0; i < 3; i++) {
+ zero_v3(cd->preview_tri[i]);
+ rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i));
+ }
+
+ SCULPT_vertex_random_access_ensure(ss);
+
+ WM_event_add_modal_handler(C, op);
+ ED_region_tag_redraw(region);
+
+ ss->draw_faded_cursor = true;
+
+ const char *status_str = TIP_(
+ "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel");
+ ED_workspace_status_text(C, status_str);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Dyntopo Detail Size";
+ ot->description = "Modify the detail size of dyntopo interactively";
+ ot->idname = "SCULPT_OT_dyntopo_detail_size_edit";
+
+ /* api callbacks */
+ ot->poll = sculpt_and_dynamic_topology_poll;
+ ot->invoke = dyntopo_detail_size_edit_invoke;
+ ot->modal = dyntopo_detail_size_edit_modal;
+ ot->cancel = dyntopo_detail_size_edit_cancel;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index aaa4bed0d2e..8b8ed42a694 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -86,37 +86,44 @@
* are only valid on parts of the mesh that are in the same connected component as the given
* initial vertices. If needed, these falloff values are propagated from vertex or grids into the
* base mesh faces.
+ *
* - On each modal callback, the operator gets the active vertex and face and gets its falloff
- * value from its precalculated falloff. This is now the active falloff value.
+ * value from its precalculated falloff. This is now the active falloff value.
* - Using the active falloff value and the settings of the expand operation (which can be modified
- * during execution using the modal keymap), the operator loops over all elements in the mesh to
- * check if they are enabled of not.
+ * during execution using the modal key-map), the operator loops over all elements in the mesh to
+ * check if they are enabled of not.
* - Based on each element state after evaluating the settings, the desired mesh data (mask, face
- * sets, colors...) is updated.
+ * sets, colors...) is updated.
*/
-/* Used for defining an invalid vertex state (for example, when the cursor is not over the mesh).
+/**
+ * Used for defining an invalid vertex state (for example, when the cursor is not over the mesh).
*/
#define SCULPT_EXPAND_VERTEX_NONE -1
-/* Used for defining an uninitialized active component index for an unused symmetry pass. */
-
+/** Used for defining an uninitialized active component index for an unused symmetry pass. */
#define EXPAND_ACTIVE_COMPONENT_NONE -1
-/* Defines how much each time the texture distortion is increased/decreased when using the modal
- * keymap. */
+/**
+ * Defines how much each time the texture distortion is increased/decreased
+ * when using the modal key-map.
+ */
#define SCULPT_EXPAND_TEXTURE_DISTORTION_STEP 0.01f
-/* This threshold offsets the required falloff value to start a new loop. This is needed because in
+/**
+ * This threshold offsets the required falloff value to start a new loop. This is needed because in
* some situations, vertices which have the same falloff value as max_falloff will start a new
- * loop, which is undesired. */
+ * loop, which is undesired.
+ */
#define SCULPT_EXPAND_LOOP_THRESHOLD 0.00001f
-/* Defines how much changes in curvature in the mesh affect the falloff shape when using normal
+/**
+ * Defines how much changes in curvature in the mesh affect the falloff shape when using normal
* falloff. This default was found experimentally and it works well in most cases, but can be
- * exposed for tweaking if needed. */
+ * exposed for tweaking if needed.
+ */
#define SCULPT_EXPAND_NORMALS_FALLOFF_EDGE_SENSITIVITY 300
-/* Expand Modal Keymap. */
+/* Expand Modal Key-map. */
enum {
SCULPT_EXPAND_MODAL_CONFIRM = 1,
SCULPT_EXPAND_MODAL_CANCEL,
@@ -143,8 +150,10 @@ enum {
* functions for getting the state of an element return true it means that data associated to that
* element will be modified by expand. */
-/* Returns true if the vertex is in a connected component with correctly initialized falloff
- * values. */
+/**
+ * Returns true if the vertex is in a connected component with correctly initialized falloff
+ * values.
+ */
static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss,
ExpandCache *expand_cache,
const int v)
@@ -157,7 +166,8 @@ static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss,
return false;
}
-/* Returns true if the face is in a connected component with correctly initialized falloff values.
+/**
+ * Returns true if the face is in a connected component with correctly initialized falloff values.
*/
static bool sculpt_expand_is_face_in_active_component(SculptSession *ss,
ExpandCache *expand_cache,
@@ -167,8 +177,10 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss,
return sculpt_expand_is_vert_in_active_component(ss, expand_cache, loop->v);
}
-/* Returns the falloff value of a vertex. This function includes texture distortion, which is not
- * precomputed into the initial falloff values. */
+/**
+ * Returns the falloff value of a vertex. This function includes texture distortion, which is not
+ * precomputed into the initial falloff values.
+ */
static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
ExpandCache *expand_cache,
const int v)
@@ -191,8 +203,10 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
return expand_cache->vert_falloff[v] + distortion;
}
-/* Returns the maximum valid falloff value stored in the falloff array, taking the maximum possible
- * texture distortion into account. */
+/**
+ * Returns the maximum valid falloff value stored in the falloff array, taking the maximum possible
+ * texture distortion into account.
+ */
static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache)
{
if (expand_cache->texture_distortion_strength == 0.0f) {
@@ -207,8 +221,9 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache)
(0.5f * expand_cache->texture_distortion_strength * expand_cache->max_vert_falloff);
}
-/* Main function to get the state of a vertex for the current state and settings of a ExpandCache.
- * Retruns true when the target data should be modified by expand.
+/**
+ * Main function to get the state of a vertex for the current state and settings of a #ExpandCache.
+ * Returns true when the target data should be modified by expand.
*/
static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v)
{
@@ -252,8 +267,10 @@ static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache
return enabled;
}
-/* Main function to get the state of a face for the current state and settings of a ExpandCache.
- * Returs true when the traget data should be modified by expand. */
+/**
+ * Main function to get the state of a face for the current state and settings of a #ExpandCache.
+ * Returns true when the target data should be modified by expand.
+ */
static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_cache, const int f)
{
if (ss->face_sets[f] <= 0) {
@@ -296,8 +313,10 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_
return enabled;
}
-/* For target modes that support gradients (such as sculpt masks or colors), this function returns
- * the corresponding gradient value for an enabled vertex. */
+/**
+ * For target modes that support gradients (such as sculpt masks or colors), this function returns
+ * the corresponding gradient value for an enabled vertex.
+ */
static float sculpt_expand_gradient_value_get(SculptSession *ss,
ExpandCache *expand_cache,
const int v)
@@ -335,8 +354,10 @@ static float sculpt_expand_gradient_value_get(SculptSession *ss,
/* Utility functions for getting all vertices state during expand. */
-/* Returns a bitmap indexed by vertex index which contains if the vertex was enabled or not for a
- * give expand_cache state. */
+/**
+ * Returns a bitmap indexed by vertex index which contains if the vertex was enabled or not for a
+ * give expand_cache state.
+ */
static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCache *expand_cache)
{
const int totvert = SCULPT_vertex_count_get(ss);
@@ -348,11 +369,13 @@ static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCa
return enabled_vertices;
}
-/* Returns a bitmap indexed by vertex index which contains if the vertex is in the boundary of the
+/**
+ * Returns a bitmap indexed by vertex index which contains if the vertex is in the boundary of the
* enabled vertices. This is defined as vertices that are enabled and at least have one connected
- * vertex that is not enabled. */
+ * vertex that is not enabled.
+ */
static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss,
- BLI_bitmap *enabled_vertices,
+ const BLI_bitmap *enabled_vertices,
const bool use_mesh_boundary)
{
const int totvert = SCULPT_vertex_count_get(ss);
@@ -383,8 +406,10 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss,
/* Functions implementing different algorithms for initializing falloff values. */
-/* Utility function to get the closet vertex after flipping an original vertex possition based on
- * an symmetry pass iteration index. */
+/**
+ * Utility function to get the closet vertex after flipping an original vertex position based on
+ * an symmetry pass iteration index.
+ */
static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob,
const char symm_it,
const int original_vertex)
@@ -402,15 +427,19 @@ static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob,
return symm_vertex;
}
-/* Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking
- * symmetry into account. */
+/**
+ * Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking
+ * symmetry into account.
+ */
static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int v)
{
return SCULPT_geodesic_from_vertex_and_symm(sd, ob, v, FLT_MAX);
}
-/* Topology: Initializes the falloff using a floodfill operation, increasing the falloff value by 1
- * when visiting a new vertex. */
+/**
+ * Topology: Initializes the falloff using a flood-fill operation,
+ * increasing the falloff value by 1 when visiting a new vertex.
+ */
typedef struct ExpandFloodFillData {
float original_normal[3];
float edge_sensitivity;
@@ -451,10 +480,11 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons
return dists;
}
-/* Normals: Floodfills the mesh and reduces the falloff depending on the normal difference between
- * each vertex and the previous one. This creates falloff pattens that follow and snap to the hard
- * edges of the object. */
-
+/**
+ * Normals: Flood-fills the mesh and reduces the falloff depending on the normal difference between
+ * each vertex and the previous one.
+ * This creates falloff patterns that follow and snap to the hard edges of the object.
+ */
static bool mask_expand_normal_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
{
@@ -521,9 +551,10 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
return dists;
}
-/* Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into
- * account. */
-
+/**
+ * Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into
+ * account.
+ */
static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
{
SculptSession *ss = ob->sculpt;
@@ -551,9 +582,11 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
return dists;
}
-/* Boundary: This falloff mode uses the code from sculpt_boundary to initialize the closest mesh
+/**
+ * Boundary: This falloff mode uses the code from sculpt_boundary to initialize the closest mesh
* boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it
- * stays parallel to the boundary, increasing the falloff value by 1 on each step. */
+ * stays parallel to the boundary, increasing the falloff value by 1 on each step.
+ */
static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const int v)
{
SculptSession *ss = ob->sculpt;
@@ -610,9 +643,11 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
return dists;
}
-/* Topology diagonals. This falloff is similar to topology, but it also considers the diagonals of
+/**
+ * Topology diagonals. This falloff is similar to topology, but it also considers the diagonals of
* the base mesh faces when checking a vertex neighbor. For this reason, this is not implement
- * using the general floodfill and sculpt neighbors accessors. */
+ * using the general flood-fill and sculpt neighbors accessors.
+ */
static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
{
SculptSession *ss = ob->sculpt;
@@ -669,11 +704,13 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
return dists;
}
-/* Functions to update the max_falloff value in the ExpandCache. These funcions are called after
+/* Functions to update the max_falloff value in the #ExpandCache. These functions are called after
* initializing a new falloff to make sure that this value is always updated. */
-/* Updates the max_falloff value for vertices in a ExpandCache based on the current values of the
- * falloff, skipping any invalid values initialized to FLT_MAX and not initialized components. */
+/**
+ * Updates the max_falloff value for vertices in a #ExpandCache based on the current values of the
+ * falloff, skipping any invalid values initialized to FLT_MAX and not initialized components.
+ */
static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss,
ExpandCache *expand_cache)
{
@@ -693,8 +730,10 @@ static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss,
}
}
-/* Updates the max_falloff value for faces in a ExpandCache based on the current values of the
- * falloff, skipping any invalid values initialized to FLT_MAX and not initialized components. */
+/**
+ * Updates the max_falloff value for faces in a ExpandCache based on the current values of the
+ * falloff, skipping any invalid values initialized to FLT_MAX and not initialized components.
+ */
static void sculpt_expand_update_max_face_falloff_factor(SculptSession *ss,
ExpandCache *expand_cache)
{
@@ -714,10 +753,12 @@ static void sculpt_expand_update_max_face_falloff_factor(SculptSession *ss,
}
}
-/* Functions to get falloff values for faces from the values from the vertices. This is used for
- * expanding Face Sets. Depending on the data type of the SculptSession, this needs to get the per
+/**
+ * Functions to get falloff values for faces from the values from the vertices. This is used for
+ * expanding Face Sets. Depending on the data type of the #SculptSession, this needs to get the per
* face falloff value from the connected vertices of each face or from the grids stored per loops
- * for each face. */
+ * for each face.
+ */
static void sculpt_expand_grids_to_faces_falloff(SculptSession *ss,
Mesh *mesh,
ExpandCache *expand_cache)
@@ -751,7 +792,9 @@ static void sculpt_expand_vertex_to_faces_falloff(Mesh *mesh, ExpandCache *expan
}
}
-/* Main function to update the faces falloff from a already calculated vertex falloff. */
+/**
+ * Main function to update the faces falloff from a already calculated vertex falloff.
+ */
static void sculpt_expand_mesh_face_falloff_from_vertex_falloff(SculptSession *ss,
Mesh *mesh,
ExpandCache *expand_cache)
@@ -777,8 +820,10 @@ static void sculpt_expand_mesh_face_falloff_from_vertex_falloff(SculptSession *s
/* Recursions. These functions will generate new falloff values based on the state of the vertices
* from the current ExpandCache options and falloff values. */
-/* Geodesic recursion: Initializes falloff values using geodesic distances from the boundary of the
- * current vertices state. */
+/**
+ * Geodesic recursion: Initializes falloff values using geodesic distances from the boundary of the
+ * current vertices state.
+ */
static void sculpt_expand_geodesics_from_state_boundary(Object *ob,
ExpandCache *expand_cache,
BLI_bitmap *enabled_vertices)
@@ -804,8 +849,10 @@ static void sculpt_expand_geodesics_from_state_boundary(Object *ob,
BLI_gset_free(initial_vertices, NULL);
}
-/* Topology recursion: Initializes falloff values using topology steps from the boundary of the
- * current vertices state, increasing the value by 1 each time a new vertex is visited. */
+/**
+ * Topology recursion: Initializes falloff values using topology steps from the boundary of the
+ * current vertices state, increasing the value by 1 each time a new vertex is visited.
+ */
static void sculpt_expand_topology_from_state_boundary(Object *ob,
ExpandCache *expand_cache,
BLI_bitmap *enabled_vertices)
@@ -837,7 +884,9 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob,
expand_cache->vert_falloff = dists;
}
-/* Main function to create a recursion step from the current ExpandCache state. */
+/**
+ * Main function to create a recursion step from the current #ExpandCache state.
+ */
static void sculpt_expand_resursion_step_add(Object *ob,
ExpandCache *expand_cache,
const eSculptExpandRecursionType recursion_type)
@@ -873,8 +922,11 @@ static void sculpt_expand_resursion_step_add(Object *ob,
}
/* Face Set Boundary falloff. */
-/* When internal falloff is set to true, the falloff will fill the active Face Set with a gradient,
- * otherwise the active Face Set will be filled with a constant falloff of 0.0f. */
+
+/**
+ * When internal falloff is set to true, the falloff will fill the active Face Set with a gradient,
+ * otherwise the active Face Set will be filled with a constant falloff of 0.0f.
+ */
static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
ExpandCache *expand_cache,
const int active_face_set,
@@ -932,8 +984,10 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
}
}
-/* Main function to initialize new falloff values in a ExpandCache given an initial vertex and a
- * falloff type. */
+/**
+ * Main function to initialize new falloff values in a #ExpandCache given an initial vertex and a
+ * falloff type.
+ */
static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(
ExpandCache *expand_cache,
Sculpt *sd,
@@ -989,9 +1043,11 @@ static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(
}
}
-/* Adds to the snapping Face Set gset all Face Sets which contain all enabled vertices for the
- * current ExpandCache state. This improves the usability of snapping, as already enabled elements
- * won't switch their state when toggling snapping with the modal keymap.*/
+/**
+ * Adds to the snapping Face Set `gset` all Face Sets which contain all enabled vertices for the
+ * current #ExpandCache state. This improves the usability of snapping, as already enabled elements
+ * won't switch their state when toggling snapping with the modal key-map.
+ */
static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss,
ExpandCache *expand_cache)
{
@@ -1035,7 +1091,9 @@ static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss,
expand_cache->invert = prev_invert_state;
}
-/* Functions to free a ExpandCache. */
+/**
+ * Functions to free a #ExpandCache.
+ */
static void sculpt_expand_cache_data_free(ExpandCache *expand_cache)
{
if (expand_cache->snap_enabled_face_sets) {
@@ -1059,7 +1117,9 @@ static void sculpt_expand_cache_free(SculptSession *ss)
ss->expand_cache = NULL;
}
-/* Functions to restore the original state from the ExpandCache when canceling the operator. */
+/**
+ * Functions to restore the original state from the #ExpandCache when canceling the operator.
+ */
static void sculpt_expand_restore_face_set_data(SculptSession *ss, ExpandCache *expand_cache)
{
PBVHNode **nodes;
@@ -1083,8 +1143,7 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
copy_v4_v4(vd.col, expand_cache->original_colors[vd.index]);
}
BKE_pbvh_vertex_iter_end;
@@ -1101,8 +1160,7 @@ static void sculpt_expand_restore_mask_data(SculptSession *ss, ExpandCache *expa
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
*vd.mask = expand_cache->original_mask[vd.index];
}
BKE_pbvh_vertex_iter_end;
@@ -1140,7 +1198,9 @@ static void sculpt_expand_restore_original_state(bContext *C,
}
}
-/* Cancel operator callback. */
+/**
+ * Cancel operator callback.
+ */
static void sculpt_expand_cancel(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
@@ -1154,7 +1214,9 @@ static void sculpt_expand_cancel(bContext *C, wmOperator *UNUSED(op))
/* Functions to update the sculpt mesh data. */
-/* Callback to update mask data per PBVH node. */
+/**
+ * Callback to update mask data per PBVH node.
+ */
static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1167,8 +1229,7 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
bool any_changed = false;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
const float initial_mask = *vd.mask;
const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index);
@@ -1201,7 +1262,9 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
}
}
-/* Update Face Set data. Not multithreaded per node as nodes don't contain face arrays. */
+/**
+ * Update Face Set data. Not multi-threaded per node as nodes don't contain face arrays.
+ */
static void sculpt_expand_face_sets_update(SculptSession *ss, ExpandCache *expand_cache)
{
const int totface = ss->totfaces;
@@ -1223,7 +1286,9 @@ static void sculpt_expand_face_sets_update(SculptSession *ss, ExpandCache *expan
}
}
-/* Callback to update vertex colors per PBVH node. */
+/**
+ * Callback to update vertex colors per PBVH node.
+ */
static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1236,8 +1301,7 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
bool any_changed = false;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
float initial_color[4];
copy_v4_v4(initial_color, vd.col);
@@ -1327,7 +1391,9 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c
}
}
-/* Restore the state of the Face Sets before a new update. */
+/**
+ * Restore the state of the Face Sets before a new update.
+ */
static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expand_cache)
{
const int totfaces = ss->totfaces;
@@ -1388,7 +1454,9 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
sculpt_expand_flush_updates(C);
}
-/* Updates the SculptSession cursor data and gets the active vertex if the cursor is over the mesh.
+/**
+ * Updates the #SculptSession cursor data and gets the active vertex
+ * if the cursor is over the mesh.
*/
static int sculpt_expand_target_vertex_update_and_get(bContext *C,
Object *ob,
@@ -1399,13 +1467,13 @@ static int sculpt_expand_target_vertex_update_and_get(bContext *C,
if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
return SCULPT_active_vertex_get(ss);
}
- else {
- return SCULPT_EXPAND_VERTEX_NONE;
- }
+ return SCULPT_EXPAND_VERTEX_NONE;
}
-/* Moves the sculpt pivot to the average point of the boundary enabled vertices of the current
- * expand state. Take symmetry and active components into account. */
+/**
+ * Moves the sculpt pivot to the average point of the boundary enabled vertices of the current
+ * expand state. Take symmetry and active components into account.
+ */
static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache *expand_cache)
{
SculptSession *ss = ob->sculpt;
@@ -1417,7 +1485,7 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
/* For boundary topology, position the pivot using only the boundary of the enabled vertices,
- * without taking mesh boundary into account. This allows to creat deformations like bending the
+ * without taking mesh boundary into account. This allows to create deformations like bending the
* mesh from the boundary of the mask that was just created. */
const float use_mesh_boundary = expand_cache->falloff_type !=
SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY;
@@ -1425,7 +1493,7 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(
ss, enabled_vertices, use_mesh_boundary);
- /* Ignore invert state, as this is the expected behaviour in most cases and mask are created in
+ /* Ignore invert state, as this is the expected behavior in most cases and mask are created in
* inverted state by default. */
expand_cache->invert = initial_invert_state;
@@ -1494,8 +1562,10 @@ static void sculpt_expand_finish(bContext *C)
ED_workspace_status_text(C, NULL);
}
-/* Finds and stores in the ExpandCache the sculpt connected component index for each symmetry pass
- * needed for expand. */
+/**
+ * Finds and stores in the #ExpandCache the sculpt connected component index for each symmetry pass
+ * needed for expand.
+ */
static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
ExpandCache *expand_cache,
const int initial_vertex)
@@ -1519,8 +1589,10 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
}
}
-/* Stores the active vertex, Face Set and mouse coordinates in the ExpandCache based on the current
- * cursor position. */
+/**
+ * Stores the active vertex, Face Set and mouse coordinates in the #ExpandCache based on the
+ * current cursor position.
+ */
static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
Object *ob,
ExpandCache *expand_cache,
@@ -1554,8 +1626,10 @@ static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
sculpt_expand_find_active_connected_components_from_vert(ob, expand_cache, initial_vertex);
}
-/* Displaces the initial mouse coordinates using the new mouse position to get a new active vertex.
- * After that, initializes a new falloff of the same type with the new active vertex. */
+/**
+ * Displaces the initial mouse coordinates using the new mouse position to get a new active vertex.
+ * After that, initializes a new falloff of the same type with the new active vertex.
+ */
static void sculpt_expand_move_propagation_origin(bContext *C,
Object *ob,
const wmEvent *event,
@@ -1579,7 +1653,9 @@ static void sculpt_expand_move_propagation_origin(bContext *C,
expand_cache->move_preview_falloff_type);
}
-/* Ensures that the SculptSession contains the required data needed for Expand. */
+/**
+ * Ensures that the #SculptSession contains the required data needed for Expand.
+ */
static void sculpt_expand_ensure_sculptsession_data(Object *ob)
{
SculptSession *ss = ob->sculpt;
@@ -1591,7 +1667,9 @@ static void sculpt_expand_ensure_sculptsession_data(Object *ob)
}
}
-/* Returns the active Face Sets ID from the enabled face or grid in the SculptSession. */
+/**
+ * Returns the active Face Sets ID from the enabled face or grid in the #SculptSession.
+ */
static int sculpt_expand_active_face_set_id_get(SculptSession *ss, ExpandCache *expand_cache)
{
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -1684,20 +1762,18 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
expand_cache->move_original_falloff_type);
break;
}
+ expand_cache->move = true;
+ expand_cache->move_original_falloff_type = expand_cache->falloff_type;
+ copy_v2_v2(expand_cache->initial_mouse_move, mouse);
+ copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse);
+ if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC &&
+ SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) {
+ /* Set to spherical falloff for preview in high poly meshes as it is the fastest one.
+ * In most cases it should match closely the preview from geodesic. */
+ expand_cache->move_preview_falloff_type = SCULPT_EXPAND_FALLOFF_SPHERICAL;
+ }
else {
- expand_cache->move = true;
- expand_cache->move_original_falloff_type = expand_cache->falloff_type;
- copy_v2_v2(expand_cache->initial_mouse_move, mouse);
- copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse);
- if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC &&
- SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) {
- /* Set to spherical falloff for preview in high poly meshes as it is the fastest one.
- * In most cases it should match closely the preview from geodesic. */
- expand_cache->move_preview_falloff_type = SCULPT_EXPAND_FALLOFF_SPHERICAL;
- }
- else {
- expand_cache->move_preview_falloff_type = expand_cache->falloff_type;
- }
+ expand_cache->move_preview_falloff_type = expand_cache->falloff_type;
}
break;
}
@@ -1804,20 +1880,23 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
}
}
- /* Update the sculpt data with the current state of the ExpandCache. */
+ /* Update the sculpt data with the current state of the #ExpandCache. */
sculpt_expand_update_for_vertex(C, ob, target_expand_vertex);
return OPERATOR_RUNNING_MODAL;
}
-/* Deletes the delete_id Face Set ID from the mesh Face Sets and stores the result in r_face_set.
- * The faces that were using the delete_id Face Set are filled using the content from their
- * neighbors. */
+/**
+ * Deletes the `delete_id` Face Set ID from the mesh Face Sets
+ * and stores the result in `r_face_set`.
+ * The faces that were using the `delete_id` Face Set are filled
+ * using the content from their neighbors.
+ */
static void sculpt_expand_delete_face_set_id(
int *r_face_sets, Mesh *mesh, MeshElemMap *pmap, const int totface, const int delete_id)
{
- /* Check that all the face sets IDs in the mesh are not equal to delete_id befor attempting to
- * delete it. */
+ /* Check that all the face sets IDs in the mesh are not equal to `delete_id`
+ * before attempting to delete it. */
bool all_same_id = true;
for (int i = 0; i < totface; i++) {
if (r_face_sets[i] != delete_id) {
@@ -1906,7 +1985,9 @@ static void sculpt_expand_cache_initial_config_set(bContext *C,
expand_cache->blend_mode = expand_cache->brush->blend;
}
-/* Does the undo sculpt push for the affected target data of the ExpandCache. */
+/**
+ * Does the undo sculpt push for the affected target data of the #ExpandCache.
+ */
static void sculpt_expand_undo_push(Object *ob, ExpandCache *expand_cache)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index df03d2adeaf..17c4beab086 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -138,8 +138,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
MeshElemMap *vert_map = &ss->pmap[vd.index];
for (int j = 0; j < ss->pmap[vd.index].count; j++) {
@@ -214,8 +213,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -447,6 +445,7 @@ typedef enum eSculptFaceSetsInitMode {
SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
+ SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES = 8,
} eSculptFaceSetsInitMode;
static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
@@ -506,6 +505,14 @@ static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
"Face Sets from Face Maps",
"Create a Face Set per Face Map",
},
+ {
+ SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES,
+ "FACE_SET_BOUNDARIES",
+ 0,
+ "Face Sets from Face Set Boundaries",
+ "Create a Face Set per isolated Face Set",
+ },
+
{0, NULL, 0, NULL, NULL},
};
@@ -557,6 +564,14 @@ static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
}
+static bool sculpt_face_sets_init_face_set_boundary_test(
+ BMesh *bm, BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float UNUSED(threshold))
+{
+ const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
+ return BM_ELEM_CD_GET_INT(from_f, cd_face_sets_offset) ==
+ BM_ELEM_CD_GET_INT(to_f, cd_face_sets_offset);
+}
+
static void sculpt_face_sets_init_flood_fill(Object *ob,
face_sets_flood_fill_test test,
const float threshold)
@@ -725,6 +740,10 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
break;
+ case SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES:
+ sculpt_face_sets_init_flood_fill(
+ ob, sculpt_face_sets_init_face_set_boundary_test, threshold);
+ break;
case SCULPT_FACE_SETS_FROM_FACE_MAPS:
sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
break;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index b5fade32a25..de9511bab6f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -110,8 +110,7 @@ static void color_filter_task_cb(void *__restrict userdata,
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float orig_color[3], final_color[4], hsv_color[3];
int hue;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 0297ed73dd4..10f141e2311 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -112,8 +112,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
contrast = -0.1f;
}
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float delta, gain, offset, max, min;
float prev_val = *vd.mask;
SculptVertexNeighborIter ni;
@@ -363,8 +362,7 @@ static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
DirtyMaskRangeData *range = tls->userdata_chunk;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float dirty_mask = neighbor_dirty_mask(ss, &vd);
range->min = min_ff(dirty_mask, range->min);
range->max = max_ff(dirty_mask, range->max);
@@ -403,8 +401,7 @@ static void dirty_mask_apply_task_cb(void *__restrict userdata,
range = 1.0f / range;
}
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float dirty_mask = neighbor_dirty_mask(ss, &vd);
float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range));
if (dirty_only) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 3cf6a8cc561..3fc1a7674f7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -302,8 +302,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
@@ -586,8 +585,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
PBVHNode *node = data->nodes[i];
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 19c4eda7593..087cb6dd94a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -792,6 +792,9 @@ typedef struct SculptThreadedTaskData {
int face_set;
int filter_undo_type;
+ int mask_init_mode;
+ int mask_init_seed;
+
ThreadMutex mutex;
} SculptThreadedTaskData;
@@ -1254,7 +1257,7 @@ typedef struct FilterCache {
float *sharpen_factor;
float (*detail_directions)[3];
- /* Filter orientaiton. */
+ /* Filter orientation. */
SculptFilterOrientation orientation;
float obmat[4][4];
float obmat_inv[4][4];
@@ -1356,10 +1359,14 @@ void SCULPT_OT_dirty_mask(struct wmOperatorType *ot);
/* Mask and Face Sets Expand. */
void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
+/* Mask Init. */
+void SCULPT_OT_mask_init(struct wmOperatorType *ot);
+
/* Detail size. */
void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
+void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
/* Dyntopo. */
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 5e229e020ad..9b06b2ee5d5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -85,8 +85,7 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
}
else {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
*vd.mask = ss->filter_cache->prev_mask[vd.index];
}
BKE_pbvh_vertex_iter_end;
@@ -114,8 +113,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
int update_it = data->mask_expand_update_it;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
int vi = vd.index;
float final_mask = *vd.mask;
if (data->mask_expand_use_normals) {
@@ -227,8 +225,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
for (int n = 0; n < ss->filter_cache->totnode; n++) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE) {
const float mask = (vd.mask) ? *vd.mask : 0.0f;
if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
if (SCULPT_check_vertex_pivot_symmetry(
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
new file mode 100644
index 00000000000..0c383cdf035
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
@@ -0,0 +1,195 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+/* Mask Init operator. */
+/* Initializes mask values for the entire mesh depending on the mode. */
+
+typedef enum eSculptMaskInitMode {
+ SCULPT_MASK_INIT_RANDOM_PER_VERTEX,
+ SCULPT_MASK_INIT_RANDOM_PER_FACE_SET,
+ SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART,
+} eSculptMaskInitMode;
+
+static EnumPropertyItem prop_sculpt_mask_init_mode_types[] = {
+ {
+ SCULPT_MASK_INIT_RANDOM_PER_VERTEX,
+ "RANDOM_PER_VERTEX",
+ 0,
+ "Random per Vertex",
+ "",
+ },
+ {
+ SCULPT_MASK_INIT_RANDOM_PER_FACE_SET,
+ "RANDOM_PER_FACE_SET",
+ 0,
+ "Random per Face Set",
+ "",
+ },
+ {
+ SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART,
+ "RANDOM_PER_LOOSE_PART",
+ 0,
+ "Random per Loose Part",
+ "",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mask_init_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+ const int mode = data->mask_init_mode;
+ const int seed = data->mask_init_seed;
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ switch (mode) {
+ case SCULPT_MASK_INIT_RANDOM_PER_VERTEX:
+ *vd.mask = BLI_hash_int_01(vd.index + seed);
+ break;
+ case SCULPT_MASK_INIT_RANDOM_PER_FACE_SET: {
+ const int face_set = SCULPT_vertex_face_set_get(ss, vd.index);
+ *vd.mask = BLI_hash_int_01(face_set + seed);
+ break;
+ }
+ case SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART:
+ *vd.mask = BLI_hash_int_01(ss->vertex_info.connected_component[vd.index] + seed);
+ break;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_node_mark_update_mask(data->nodes[i]);
+}
+
+static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (totnode == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin(ob, "init mask");
+
+ if (mode == SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART) {
+ SCULPT_connected_components_ensure(ob);
+ }
+
+ SculptThreadedTaskData data = {
+ .ob = ob,
+ .nodes = nodes,
+ .mask_init_mode = mode,
+ .mask_init_seed = PIL_check_seconds_timer(),
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_init_task_cb, &settings);
+
+ multires_stitch_grids(ob);
+
+ SCULPT_undo_push_end();
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ MEM_SAFE_FREE(nodes);
+ SCULPT_tag_update_overlays(C);
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_mask_init(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Init Mask";
+ ot->description = "Creates a new mask for the entire mesh";
+ ot->idname = "SCULPT_OT_mask_init";
+
+ /* api callbacks */
+ ot->exec = sculpt_mask_init_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_mask_init_mode_types,
+ SCULPT_MASK_INIT_RANDOM_PER_VERTEX,
+ "Mode",
+ "");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index cfc31e1dcdd..f78f30a2cfd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -85,8 +85,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
test_radius *= brush->normal_radius_factor;
test.radius_squared = test_radius * test_radius;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -166,8 +165,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 5fdf8415f28..c3977b28178 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -85,8 +85,7 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -139,8 +138,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
BKE_brush_color_get(ss->scene, brush));
IMB_colormanagement_srgb_to_scene_linear_v3(brush_color);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
bool affect_vertex = false;
@@ -227,8 +225,7 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata,
test.radius *= data->brush->wet_paint_radius_factor;
test.radius_squared = test.radius * test.radius;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -384,8 +381,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -454,8 +450,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.index));
}
BKE_pbvh_vertex_iter_end;
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index a85f805894b..4d2a1bf13dc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -174,8 +174,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float total_disp[3];
@@ -232,8 +231,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
const char symm = SCULPT_mesh_symmetry_xyz_get(data->ob);
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SculptVertexNeighborIter ni;
float max = 0.0f;
@@ -605,8 +603,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SculptVertexNeighborIter ni;
float avg = 0.0f;
int total = 0;
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 4c0795eb0f7..61984610a5a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -229,8 +229,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -312,8 +311,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -473,8 +471,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -516,8 +513,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index 4554ea178ab..3c0a591e8a7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -164,8 +164,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float transformed_co[3], orig_co[3], disp[3];
float *start_co;
@@ -335,8 +334,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
for (int n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
const float mask = (vd.mask) ? *vd.mask : 0.0f;
if (mask < 1.0f) {
if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
@@ -354,8 +352,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
for (int n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
const float mask = (vd.mask) ? *vd.mask : 0.0f;
if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index ec103bd2b98..b6205db6f45 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1104,8 +1104,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if (vd.no) {
copy_v3_v3_short(unode->no[vd.i], vd.no);
@@ -1147,8 +1146,7 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
unode->mask[vd.i] = *vd.mask;
}
BKE_pbvh_vertex_iter_end;
@@ -1159,8 +1157,7 @@ static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v4_v4(unode->col[vd.i], vd.col);
}
BKE_pbvh_vertex_iter_end;
@@ -1258,8 +1255,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
case SCULPT_UNDO_MASK:
/* Before any vertex values get modified, ensure their
* original positions are logged. */
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
}
BKE_pbvh_vertex_iter_end;
@@ -1268,8 +1264,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
case SCULPT_UNDO_HIDDEN: {
GSetIterator gs_iter;
GSet *faces = BKE_pbvh_bmesh_node_faces(node);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
- {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
}
BKE_pbvh_vertex_iter_end;
@@ -1492,8 +1487,11 @@ static void sculpt_undosys_step_decode_redo_impl(struct bContext *C,
static void sculpt_undosys_step_decode_undo(struct bContext *C,
Depsgraph *depsgraph,
- SculptUndoStep *us)
+ SculptUndoStep *us,
+ const bool is_final)
{
+ /* Walk forward over any applied steps of same type,
+ * then walk back in the next loop, un-applying them. */
SculptUndoStep *us_iter = us;
while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
if (us_iter->step.next->is_applied == false) {
@@ -1501,8 +1499,13 @@ static void sculpt_undosys_step_decode_undo(struct bContext *C,
}
us_iter = (SculptUndoStep *)us_iter->step.next;
}
- while (us_iter != us) {
+
+ while ((us_iter != us) || (!is_final && us_iter == us)) {
+ BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
sculpt_undosys_step_decode_undo_impl(C, depsgraph, us_iter);
+ if (us_iter == us) {
+ break;
+ }
us_iter = (SculptUndoStep *)us_iter->step.prev;
}
}
@@ -1527,12 +1530,10 @@ static void sculpt_undosys_step_decode_redo(struct bContext *C,
}
}
-static void sculpt_undosys_step_decode(struct bContext *C,
- struct Main *bmain,
- UndoStep *us_p,
- const eUndoStepDir dir,
- bool UNUSED(is_final))
+static void sculpt_undosys_step_decode(
+ struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
{
+ /* NOTE: behavior for undo/redo closely matches image undo. */
BLI_assert(dir != STEP_INVALID);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@@ -1574,7 +1575,7 @@ static void sculpt_undosys_step_decode(struct bContext *C,
SculptUndoStep *us = (SculptUndoStep *)us_p;
if (dir == STEP_UNDO) {
- sculpt_undosys_step_decode_undo(C, depsgraph, us);
+ sculpt_undosys_step_decode_undo(C, depsgraph, us, is_final);
}
else if (dir == STEP_REDO) {
sculpt_undosys_step_decode_redo(C, depsgraph, us);
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 3a584a7f0cb..efa714e315d 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -663,11 +663,11 @@ static int action_unlink_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* NOTE: this is hardcoded to match the behavior for the unlink button
* (in interface_templates.c). */
- RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0);
+ RNA_boolean_set(op->ptr, "force_delete", event->shift != 0);
return action_unlink_exec(C, op);
}
diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt
index 573afb76f0e..85c07223f2d 100644
--- a/source/blender/editors/space_api/CMakeLists.txt
+++ b/source/blender/editors/space_api/CMakeLists.txt
@@ -50,6 +50,7 @@ set(LIB
bf_editor_space_outliner
bf_editor_space_script
bf_editor_space_sequencer
+ bf_editor_space_spreadsheet
bf_editor_space_statusbar
bf_editor_space_text
bf_editor_space_topbar
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 1bd8d13b25b..adb824b8934 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -95,6 +95,7 @@ void ED_spacetypes_init(void)
ED_spacetype_clip();
ED_spacetype_statusbar();
ED_spacetype_topbar();
+ ED_spacetype_spreadsheet();
/* Register operator types for screen and all spaces. */
ED_operatortypes_userpref();
@@ -262,7 +263,7 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle)
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
{
- LISTBASE_FOREACH (RegionDrawCB *, rdc, &region->type->drawcalls) {
+ LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &region->type->drawcalls) {
if (rdc->type == type) {
rdc->draw(C, region, rdc->customdata);
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 3efaff72637..13762b348c2 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -33,6 +33,7 @@
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_collection_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -153,6 +154,29 @@ static bool buttons_context_path_world(ButsContextPath *path)
return false;
}
+static bool buttons_context_path_collection(ButsContextPath *path, wmWindow *window)
+{
+ PointerRNA *ptr = &path->ptr[path->len - 1];
+
+ /* if we already have a (pinned) collection, we're done */
+ if (RNA_struct_is_a(ptr->type, &RNA_Collection)) {
+ return true;
+ }
+ /* if we have a view layer, use the view layer's active collection */
+ if (buttons_context_path_view_layer(path, window)) {
+ ViewLayer *view_layer = path->ptr[path->len - 1].data;
+ Collection *c = view_layer->active_collection->collection;
+ if (c) {
+ RNA_id_pointer_create(&c->id, &path->ptr[path->len]);
+ path->len++;
+ return true;
+ }
+ }
+
+ /* no path to a collection possible */
+ return false;
+}
+
static bool buttons_context_path_linestyle(ButsContextPath *path, wmWindow *window)
{
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -575,6 +599,9 @@ static bool buttons_context_path(
case BCONTEXT_WORLD:
found = buttons_context_path_world(path);
break;
+ case BCONTEXT_COLLECTION: /* This is for Line Art collection flags */
+ found = buttons_context_path_collection(path, window);
+ break;
case BCONTEXT_TOOL:
found = true;
break;
@@ -858,6 +885,10 @@ int /*eContextResult*/ buttons_context(const bContext *C,
set_pointer_type(path, result, &RNA_World);
return CTX_RESULT_OK;
}
+ if (CTX_data_equals(member, "collection")) {
+ set_pointer_type(path, result, &RNA_Collection);
+ return 1;
+ }
if (CTX_data_equals(member, "object")) {
set_pointer_type(path, result, &RNA_Object);
return CTX_RESULT_OK;
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 07bc1d42c3f..43d45db38e2 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -206,6 +206,14 @@ int ED_buttons_tabs_list(SpaceProperties *sbuts, short *context_tabs_array)
context_tabs_array[length] = -1;
length++;
}
+ if (sbuts->pathflag & (1 << BCONTEXT_VIEW_LAYER)) {
+ context_tabs_array[length] = BCONTEXT_COLLECTION;
+ length++;
+ }
+ if (length != 0) {
+ context_tabs_array[length] = -1;
+ length++;
+ }
if (sbuts->pathflag & (1 << BCONTEXT_OBJECT)) {
context_tabs_array[length] = BCONTEXT_OBJECT;
length++;
@@ -271,6 +279,8 @@ static const char *buttons_main_region_context_string(const short mainb)
return "view_layer";
case BCONTEXT_WORLD:
return "world";
+ case BCONTEXT_COLLECTION:
+ return "collection";
case BCONTEXT_OBJECT:
return "object";
case BCONTEXT_DATA:
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index e1172458f67..36375ad1ef3 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -269,6 +269,23 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
return NULL;
}
+bool ED_space_clip_get_position(struct SpaceClip *sc,
+ struct ARegion *ar,
+ int mval[2],
+ float fpos[2])
+{
+ ImBuf *ibuf = ED_space_clip_get_buffer(sc);
+ if (!ibuf) {
+ return false;
+ }
+
+ /* map the mouse coords to the backdrop image space */
+ ED_clip_mouse_pos(sc, ar, mval, fpos);
+
+ IMB_freeImBuf(ibuf);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
{
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index b65dc909d5f..96504651e44 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -244,7 +244,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
/* add modal handler for ESC */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index e480ec2db05..9882304d97d 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -356,7 +356,7 @@ static int track_markers(bContext *C, wmOperator *op, bool use_job)
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
/* Add modal handler for ESC. */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 56fb588776e..309b280177c 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -75,6 +75,7 @@ void FILE_OT_rename(struct wmOperatorType *ot);
void FILE_OT_smoothscroll(struct wmOperatorType *ot);
void FILE_OT_filepath_drop(struct wmOperatorType *ot);
void FILE_OT_start_filter(struct wmOperatorType *ot);
+void FILE_OT_view_selected(struct wmOperatorType *ot);
void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but);
void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
@@ -112,6 +113,21 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
+typedef void *onReloadFnData;
+typedef void (*onReloadFn)(struct SpaceFile *space_data, onReloadFnData custom_data);
+typedef struct SpaceFile_Runtime {
+ /* Called once after the file browser has reloaded. Reset to NULL after calling.
+ * Use file_on_reload_callback_register() to register a callback. */
+ onReloadFn on_reload;
+ onReloadFnData on_reload_custom_data;
+} SpaceFile_Runtime;
+
+/* Register an on-reload callback function. Note that there can only be one such function at a
+ * time; registering a new one will overwrite the previous one. */
+void file_on_reload_callback_register(struct SpaceFile *sfile,
+ onReloadFn callback,
+ onReloadFnData custom_data);
+
/* file_panels.c */
void file_tool_props_region_panels_register(struct ARegionType *art);
void file_execute_region_panels_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 985c92f19b6..bd6b15bdf74 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -256,6 +256,33 @@ static bool file_is_any_selected(struct FileList *files)
return false;
}
+static FileSelection file_current_selection_range_get(struct FileList *files)
+{
+ const int numfiles = filelist_files_ensure(files);
+ FileSelection selection = {-1, -1};
+
+ /* Iterate over the files once but in two loops, one to find the first selected file, and the
+ * other to find the last. */
+
+ int file_index;
+ for (file_index = 0; file_index < numfiles; file_index++) {
+ if (filelist_entry_is_selected(files, file_index)) {
+ /* First selected entry found. */
+ selection.first = file_index;
+ break;
+ }
+ }
+
+ for (; file_index < numfiles; file_index++) {
+ if (filelist_entry_is_selected(files, file_index)) {
+ selection.last = file_index;
+ /* Keep looping, we may find more selected files. */
+ }
+ }
+
+ return selection;
+}
+
/**
* If \a file is outside viewbounds, this adjusts view to make sure it's inside
*/
@@ -299,6 +326,24 @@ static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, con
}
}
+static void file_ensure_selection_inside_viewbounds(ARegion *region,
+ SpaceFile *sfile,
+ FileSelection *sel)
+{
+ const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
+
+ if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) &&
+ ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h))) {
+ return;
+ }
+
+ /* Adjust view to display selection. Doing iterations for first and last
+ * selected item makes view showing as much of the selection possible.
+ * Not really useful if tiles are (almost) bigger than viewbounds though. */
+ file_ensure_inside_viewbounds(region, sfile, sel->last);
+ file_ensure_inside_viewbounds(region, sfile, sel->first);
+}
+
static FileSelect file_select(
bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
{
@@ -330,16 +375,7 @@ static FileSelect file_select(
}
else if (sel.last >= 0) {
ARegion *region = CTX_wm_region(C);
- const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
-
- /* Adjust view to display selection. Doing iterations for first and last
- * selected item makes view showing as much of the selection possible.
- * Not really useful if tiles are (almost) bigger than viewbounds though. */
- if (((layout->flag & FILE_LAYOUT_HOR) && region->winx > (1.2f * layout->tile_w)) ||
- ((layout->flag & FILE_LAYOUT_VER) && region->winy > (2.0f * layout->tile_h))) {
- file_ensure_inside_viewbounds(region, sfile, sel.last);
- file_ensure_inside_viewbounds(region, sfile, sel.first);
- }
+ file_ensure_selection_inside_viewbounds(region, sfile, &sel);
}
/* update operator for name change event */
@@ -926,6 +962,55 @@ void FILE_OT_select_all(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
+
+static int file_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ FileSelection sel = file_current_selection_range_get(sfile->files);
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ if (sel.first == -1 && sel.last == -1 && params->active_file == -1) {
+ /* Nothing was selected. */
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Extend the selection area with the active file, as it may not be selected but still is
+ * important to have in view. */
+ if (sel.first == -1 || params->active_file < sel.first) {
+ sel.first = params->active_file;
+ }
+ if (sel.last == -1 || params->active_file > sel.last) {
+ sel.last = params->active_file;
+ }
+
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ file_ensure_selection_inside_viewbounds(region, sfile, &sel);
+
+ file_draw_check(C);
+ WM_event_add_mousemove(CTX_wm_window(C));
+ ED_area_tag_redraw(area);
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_view_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Frame Selected";
+ ot->description = "Scroll the selected files into view";
+ ot->idname = "FILE_OT_view_selected";
+
+ /* api callbacks */
+ ot->exec = file_view_selected_exec;
+ ot->poll = ED_operator_file_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Select Bookmark Operator
* \{ */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 33c37875372..f5ec9a0e8a1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -410,14 +410,14 @@ typedef struct FileList {
/* Set given path as root directory,
* if last bool is true may change given string in place to a valid value.
* Returns True if valid dir. */
- bool (*checkdirf)(struct FileList *, char *, const bool);
+ bool (*check_dir_fn)(struct FileList *, char *, const bool);
/* Fill filelist (to be called by read job). */
- void (*read_jobf)(
+ void (*read_job_fn)(
Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
/* Filter an entry of current filelist. */
- bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *);
+ bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *);
short tags; /* FileListTags */
} FileList;
@@ -963,7 +963,7 @@ void filelist_filter(FileList *filelist)
/* Filter remap & count how many files are left after filter in a single loop. */
for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
- if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) {
+ if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) {
filtered_tmp[num_filtered++] = file;
}
}
@@ -1742,25 +1742,25 @@ void filelist_settype(FileList *filelist, short type)
filelist->tags = 0;
switch (filelist->type) {
case FILE_MAIN:
- filelist->checkdirf = filelist_checkdir_main;
- filelist->read_jobf = filelist_readjob_main;
- filelist->filterf = is_filtered_main;
+ filelist->check_dir_fn = filelist_checkdir_main;
+ filelist->read_job_fn = filelist_readjob_main;
+ filelist->filter_fn = is_filtered_main;
break;
case FILE_LOADLIB:
- filelist->checkdirf = filelist_checkdir_lib;
- filelist->read_jobf = filelist_readjob_lib;
- filelist->filterf = is_filtered_lib;
+ filelist->check_dir_fn = filelist_checkdir_lib;
+ filelist->read_job_fn = filelist_readjob_lib;
+ filelist->filter_fn = is_filtered_lib;
break;
case FILE_MAIN_ASSET:
- filelist->checkdirf = filelist_checkdir_main_assets;
- filelist->read_jobf = filelist_readjob_main_assets;
- filelist->filterf = is_filtered_main_assets;
+ filelist->check_dir_fn = filelist_checkdir_main_assets;
+ filelist->read_job_fn = filelist_readjob_main_assets;
+ filelist->filter_fn = is_filtered_main_assets;
filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS;
break;
default:
- filelist->checkdirf = filelist_checkdir_dir;
- filelist->read_jobf = filelist_readjob_dir;
- filelist->filterf = is_filtered_file;
+ filelist->check_dir_fn = filelist_checkdir_dir;
+ filelist->read_job_fn = filelist_readjob_dir;
+ filelist->filter_fn = is_filtered_file;
break;
}
@@ -1867,7 +1867,7 @@ const char *filelist_dir(struct FileList *filelist)
bool filelist_is_dir(struct FileList *filelist, const char *path)
{
- return filelist->checkdirf(filelist, (char *)path, false);
+ return filelist->check_dir_fn(filelist, (char *)path, false);
}
/**
@@ -1879,7 +1879,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir);
- const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid);
+ const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid);
BLI_assert(is_valid_path || allow_invalid);
UNUSED_VARS_NDEBUG(is_valid_path);
@@ -1990,9 +1990,7 @@ static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
filelist_entry_free(entry);
}
-static FileDirEntry *filelist_file_ex(struct FileList *filelist,
- const int index,
- const bool use_request)
+FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
{
FileDirEntry *ret = NULL, *old;
FileListEntryCache *cache = &filelist->filelist_cache;
@@ -2703,6 +2701,19 @@ uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCh
return 0;
}
+bool filelist_entry_is_selected(FileList *filelist, const int index)
+{
+ BLI_assert(index >= 0 && index < filelist->filelist.nbr_entries_filtered);
+ FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
+
+ /* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to
+ * "not selected". */
+ const uint selection_state = POINTER_AS_UINT(
+ BLI_ghash_lookup(filelist->selection_state, intern_entry->uuid));
+
+ return selection_state != 0;
+}
+
/**
* Set selection of the '..' parent entry, but only if it's actually visible.
*/
@@ -3358,13 +3369,13 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
BLI_mutex_unlock(&flrj->lock);
- flrj->tmp_filelist->read_jobf(flrj->current_main,
- flrj->tmp_filelist,
- flrj->main_name,
- stop,
- do_update,
- progress,
- &flrj->lock);
+ flrj->tmp_filelist->read_job_fn(flrj->current_main,
+ flrj->tmp_filelist,
+ flrj->main_name,
+ stop,
+ do_update,
+ progress,
+ &flrj->lock);
}
static void filelist_readjob_update(void *flrjv)
@@ -3464,7 +3475,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
filelist_readjob_endjob(flrj);
filelist_readjob_free(flrj);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL);
return;
}
@@ -3476,7 +3487,10 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
WM_JOB_PROGRESS,
WM_JOB_TYPE_FILESEL_READDIR);
WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
- WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
+ WM_jobs_timer(wm_job,
+ 0.01,
+ NC_SPACE | ND_SPACE_FILE_LIST,
+ NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED);
WM_jobs_callbacks(
wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 16984bb6e43..9eb70dd8437 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -93,6 +93,8 @@ void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
+FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
+
int filelist_file_findpath(struct FileList *filelist, const char *file);
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
@@ -126,6 +128,7 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
+bool filelist_entry_is_selected(struct FileList *filelist, const int index);
void filelist_entry_parent_select_set(struct FileList *filelist,
FileSelType select,
unsigned int flag,
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 6917893ab5f..7015ca970a3 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -454,6 +454,66 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
}
+struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile)
+{
+ if (!ED_fileselect_is_asset_browser(sfile)) {
+ return NULL;
+ }
+
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ return filelist_file_get_id(file);
+}
+
+static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
+{
+ ID *asset_id = (ID *)custom_data;
+ ED_fileselect_activate_by_id(sfile, asset_id, false);
+}
+
+void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred)
+{
+ if (!ED_fileselect_is_asset_browser(sfile)) {
+ return;
+ }
+
+ /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
+ * there is a fair chance that the to-be-activated ID will only be present after these operations
+ * have completed. Defer activation until then. */
+ if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) {
+ /* This should be thread-safe, as this function is likely called from the main thread, and
+ * notifiers (which cause a call to the on-reload callback function) are handled on the main
+ * thread as well. */
+ file_on_reload_callback_register(sfile, on_reload_activate_by_id, asset_id);
+ return;
+ }
+
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ struct FileList *files = sfile->files;
+
+ const int num_files_filtered = filelist_files_ensure(files);
+ for (int file_index = 0; file_index < num_files_filtered; ++file_index) {
+ const FileDirEntry *file = filelist_file_ex(files, file_index, false);
+
+ if (filelist_file_get_id(file) != asset_id) {
+ filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ continue;
+ }
+
+ params->active_file = file_index;
+ filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+
+ /* Keep looping to deselect the other files. */
+ }
+
+ WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL);
+}
+
/* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA
* may also be remembered, but only conditionally. */
#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT)
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index b175844a710..993b1d9b69c 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -173,6 +173,7 @@ static void file_free(SpaceLink *sl)
MEM_SAFE_FREE(sfile->params);
MEM_SAFE_FREE(sfile->asset_params);
+ MEM_SAFE_FREE(sfile->runtime);
if (sfile->layout) {
MEM_freeN(sfile->layout);
@@ -188,6 +189,12 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area)
if (sfile->layout) {
sfile->layout->dirty = true;
}
+
+ if (sfile->runtime == NULL) {
+ sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__);
+ }
+ /* Validate the params right after file read. */
+ fileselect_refresh_params(sfile);
}
static void file_exit(wmWindowManager *wm, ScrArea *area)
@@ -209,6 +216,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
sfilen->op = NULL; /* file window doesn't own operators */
+ sfilen->runtime = NULL;
sfilen->previews_timer = NULL;
sfilen->smoothscroll_timer = NULL;
@@ -392,6 +400,35 @@ static void file_refresh(const bContext *C, ScrArea *area)
ED_area_tag_redraw(area);
}
+void file_on_reload_callback_register(SpaceFile *sfile,
+ onReloadFn callback,
+ onReloadFnData custom_data)
+{
+ sfile->runtime->on_reload = callback;
+ sfile->runtime->on_reload_custom_data = custom_data;
+}
+
+static void file_on_reload_callback_call(SpaceFile *sfile)
+{
+ if (sfile->runtime->on_reload == NULL) {
+ return;
+ }
+
+ sfile->runtime->on_reload(sfile, sfile->runtime->on_reload_custom_data);
+
+ sfile->runtime->on_reload = NULL;
+ sfile->runtime->on_reload_custom_data = NULL;
+}
+
+static void file_reset_filelist_showing_main_data(ScrArea *area, SpaceFile *sfile)
+{
+ if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
+ /* Full refresh of the file list if local asset data was changed. Refreshing this view
+ * is cheap and users expect this to be updated immediately. */
+ file_tag_reset_list(area, sfile);
+ }
+}
+
static void file_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
@@ -418,13 +455,29 @@ static void file_listener(const wmSpaceTypeListenerParams *params)
ED_area_tag_refresh(area);
}
break;
+ case ND_SPACE_CHANGED:
+ /* If the space was just turned into a file/asset browser, the file-list may need to be
+ * updated to reflect latest changes in main data. */
+ file_reset_filelist_showing_main_data(area, sfile);
+ break;
+ }
+ switch (wmn->action) {
+ case NA_JOB_FINISHED:
+ file_on_reload_callback_call(sfile);
+ break;
}
break;
case NC_ASSET: {
- if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
- /* Full refresh of the file list if local asset data was changed. Refreshing this view is
- * cheap and users expect this to be updated immediately. */
- file_tag_reset_list(area, sfile);
+ switch (wmn->action) {
+ case NA_SELECTED:
+ case NA_ACTIVATED:
+ ED_area_tag_refresh(area);
+ break;
+ case NA_ADDED:
+ case NA_REMOVED:
+ case NA_EDITED:
+ file_reset_filelist_showing_main_data(area, sfile);
+ break;
}
break;
}
@@ -464,8 +517,7 @@ static void file_main_region_listener(const wmRegionListenerParams *params)
}
break;
case NC_ID:
- if (ELEM(wmn->action, NA_RENAME)) {
- /* In case the filelist shows ID names. */
+ if (ELEM(wmn->action, NA_SELECTED, NA_ACTIVATED, NA_RENAME)) {
ED_region_tag_redraw(region);
}
break;
@@ -620,6 +672,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_smoothscroll);
WM_operatortype_append(FILE_OT_filepath_drop);
WM_operatortype_append(FILE_OT_start_filter);
+ WM_operatortype_append(FILE_OT_view_selected);
}
/* NOTE: do not add .blend file reading on this level */
@@ -847,13 +900,11 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *
{
SpaceFile *sfile = (SpaceFile *)sl;
- /* If the file shows main data (IDs), tag it for reset. */
- if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
- /* Full refresh of the file list if main data was changed, don't even attempt remap pointers.
- * We could give file list types a id-remap callback, but it's probably not worth it.
- * Refreshing local file lists is relatively cheap. */
- file_tag_reset_list(area, sfile);
- }
+ /* If the file shows main data (IDs), tag it for reset.
+ * Full reset of the file list if main data was changed, don't even attempt remap pointers.
+ * We could give file list types a id-remap callback, but it's probably not worth it.
+ * Refreshing local file lists is relatively cheap. */
+ file_reset_filelist_showing_main_data(area, sfile);
}
/* only called once, from space/spacetypes.c */
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 4752f62b58c..c5358cdfa5b 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -35,6 +35,7 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -579,8 +580,13 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu)
/* Helper func - just draw the F-Curve by sampling the visible region
* (for drawing curves with modifiers). */
-static void draw_fcurve_curve(
- bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2d, uint pos, const bool use_nla_remap)
+static void draw_fcurve_curve(bAnimContext *ac,
+ ID *id,
+ FCurve *fcu_,
+ View2D *v2d,
+ uint pos,
+ const bool use_nla_remap,
+ const bool draw_extrapolation)
{
SpaceGraph *sipo = (SpaceGraph *)ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
@@ -641,40 +647,90 @@ static void draw_fcurve_curve(
/* the start/end times are simply the horizontal extents of the 'cur' rect */
float stime = v2d->cur.xmin;
- float etime = v2d->cur.xmax +
- samplefreq; /* + samplefreq here so that last item gets included... */
+ float etime = v2d->cur.xmax;
- /* at each sampling interval, add a new vertex
- * - apply the unit correction factor to the calculated values so that
- * the displayed values appear correctly in the viewport
- */
+ AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL;
+
+ /* If not drawing extrapolation, then change fcurve drawing bounds to its keyframe bounds clamped
+ * by graph editor bounds. */
+ if (!draw_extrapolation) {
+ float fcu_start = 0;
+ float fcu_end = 0;
+ BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false, false);
- int n = roundf((etime - stime) / samplefreq);
+ fcu_start = BKE_nla_tweakedit_remap(adt, fcu_start, NLATIME_CONVERT_MAP);
+ fcu_end = BKE_nla_tweakedit_remap(adt, fcu_end, NLATIME_CONVERT_MAP);
- if (n > 0) {
- immBegin(GPU_PRIM_LINE_STRIP, (n + 1));
+ /* Account for reversed NLA strip effect. */
+ if (fcu_end < fcu_start) {
+ SWAP(float, fcu_start, fcu_end);
+ }
- AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL;
- /* NLA remapping is linear so we don't have to remap per iteration. */
- const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP);
- const float eval_freq = BKE_nla_tweakedit_remap(
- adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) -
- eval_start;
+ /* Clamp to graph editor rendering bounds. */
+ stime = max_ff(stime, fcu_start);
+ etime = min_ff(etime, fcu_end);
+ }
+
+ const int total_samples = roundf((etime - stime) / samplefreq);
+ if (total_samples <= 0) {
+ return;
+ }
- for (int i = 0; i <= n; i++) {
- float ctime = stime + i * samplefreq;
- const float eval_time = eval_start + i * eval_freq;
- immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac);
+ /* NLA remapping is linear so we don't have to remap per iteration. */
+ const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP);
+ const float eval_freq = BKE_nla_tweakedit_remap(adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) -
+ eval_start;
+ const float eval_end = BKE_nla_tweakedit_remap(adt, etime, NLATIME_CONVERT_UNMAP);
+
+ immBegin(GPU_PRIM_LINE_STRIP, (total_samples + 1));
+
+ /* At each sampling interval, add a new vertex.
+ *
+ * Apply the unit correction factor to the calculated values so that the displayed values appear
+ * correctly in the viewport.
+ */
+ for (int i = 0; i < total_samples; i++) {
+ const float ctime = stime + i * samplefreq;
+ float eval_time = eval_start + i * eval_freq;
+
+ /* Prevent drawing past bounds, due to floating point problems.
+ * User-wise, prevent visual flickering.
+ *
+ * This is to cover the case where:
+ * eval_start + total_samples * eval_freq > eval_end
+ * due to floating point problems.
+ */
+ if (eval_time > eval_end) {
+ eval_time = eval_end;
}
- immEnd();
+ immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac);
}
+
+ /* Ensure we include end boundary point.
+ * User-wise, prevent visual flickering.
+ *
+ * This is to cover the case where:
+ * eval_start + total_samples * eval_freq < eval_end
+ * due to floating point problems.
+ */
+ immVertex2f(pos, etime, (evaluate_fcurve(&fcurve_for_draw, eval_end) + offset) * unitFac);
+
+ immEnd();
}
/* helper func - draw a samples-based F-Curve */
-static void draw_fcurve_curve_samples(
- bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, const uint shdr_pos)
+static void draw_fcurve_curve_samples(bAnimContext *ac,
+ ID *id,
+ FCurve *fcu,
+ View2D *v2d,
+ const uint shdr_pos,
+ const bool draw_extrapolation)
{
+ if (!draw_extrapolation && fcu->totvert == 1) {
+ return;
+ }
+
FPoint *prevfpt = fcu->fpt;
FPoint *fpt = prevfpt + 1;
float fac, v[2];
@@ -683,11 +739,13 @@ static void draw_fcurve_curve_samples(
short mapping_flag = ANIM_get_normalization_flags(ac);
int count = fcu->totvert;
- if (prevfpt->vec[0] > v2d->cur.xmin) {
+ const bool extrap_left = draw_extrapolation && prevfpt->vec[0] > v2d->cur.xmin;
+ if (extrap_left) {
count++;
}
- if ((prevfpt + b - 1)->vec[0] < v2d->cur.xmax) {
+ const bool extrap_right = draw_extrapolation && (prevfpt + b - 1)->vec[0] < v2d->cur.xmax;
+ if (extrap_right) {
count++;
}
@@ -700,7 +758,7 @@ static void draw_fcurve_curve_samples(
immBegin(GPU_PRIM_LINE_STRIP, count);
/* extrapolate to left? - left-side of view comes before first keyframe? */
- if (prevfpt->vec[0] > v2d->cur.xmin) {
+ if (extrap_left) {
v[0] = v2d->cur.xmin;
/* y-value depends on the interpolation */
@@ -734,7 +792,7 @@ static void draw_fcurve_curve_samples(
}
/* extrapolate to right? (see code for left-extrapolation above too) */
- if (prevfpt->vec[0] < v2d->cur.xmax) {
+ if (extrap_right) {
v[0] = v2d->cur.xmax;
/* y-value depends on the interpolation */
@@ -779,8 +837,13 @@ static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu)
}
/* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */
-static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos)
+static void draw_fcurve_curve_bezts(
+ bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos, const bool draw_extrapolation)
{
+ if (!draw_extrapolation && fcu->totvert == 1) {
+ return;
+ }
+
BezTriple *prevbezt = fcu->bezt;
BezTriple *bezt = prevbezt + 1;
float v1[2], v2[2], v3[2], v4[2];
@@ -803,7 +866,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * 32 + 3));
/* extrapolate to left? */
- if (prevbezt->vec[1][0] > v2d->cur.xmin) {
+ if (draw_extrapolation && prevbezt->vec[1][0] > v2d->cur.xmin) {
/* left-side of view comes before first keyframe, so need to extend as not cyclic */
v1[0] = v2d->cur.xmin;
@@ -923,7 +986,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
}
/* extrapolate to right? (see code for left-extrapolation above too) */
- if (prevbezt->vec[1][0] < v2d->cur.xmax) {
+ if (draw_extrapolation && prevbezt->vec[1][0] < v2d->cur.xmax) {
v1[0] = v2d->cur.xmax;
/* y-value depends on the interpolation */
@@ -1026,6 +1089,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
immUniformColor3fvAlpha(fcu->color, fcurve_display_alpha(fcu));
}
+ const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0;
/* draw F-Curve */
if ((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) {
/* draw a curve affected by modifiers or only allowed to have integer values
@@ -1039,25 +1103,25 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
* curve itself. Afterward, we go back and redo the keyframe remapping so the controls are
* drawn properly. */
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, true, false);
- draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, true);
+ draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, true, draw_extrapolation);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, false, false);
}
else {
- draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false);
+ draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false, draw_extrapolation);
}
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
/* just draw curve based on defined data (i.e. no modifiers) */
if (fcu->bezt) {
if (fcurve_can_use_simple_bezt_drawing(fcu)) {
- draw_fcurve_curve_bezts(ac, ale->id, fcu, &region->v2d, shdr_pos);
+ draw_fcurve_curve_bezts(ac, ale->id, fcu, &region->v2d, shdr_pos, draw_extrapolation);
}
else {
- draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false);
+ draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false, draw_extrapolation);
}
}
else if (fcu->fpt) {
- draw_fcurve_curve_samples(ac, ale->id, fcu, &region->v2d, shdr_pos);
+ draw_fcurve_curve_samples(ac, ale->id, fcu, &region->v2d, shdr_pos, draw_extrapolation);
}
}
@@ -1278,6 +1342,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
immUniform1f("dash_width", 20.0f);
immUniform1f("dash_factor", 0.5f);
+ const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0;
/* the ghost curves are simply sampled F-Curves stored in sipo->runtime.ghost_curves */
for (fcu = sipo->runtime.ghost_curves.first; fcu; fcu = fcu->next) {
/* set whatever color the curve has set
@@ -1287,7 +1352,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
immUniformColor3fvAlpha(fcu->color, 0.5f);
/* simply draw the stored samples */
- draw_fcurve_curve_samples(ac, NULL, fcu, &region->v2d, shdr_pos);
+ draw_fcurve_curve_samples(ac, NULL, fcu, &region->v2d, shdr_pos, draw_extrapolation);
}
immUnbindProgram();
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 3e52dc7377b..4174e1c63ae 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -187,11 +187,11 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
strcpy(mode_str, TIP_("Decimate Keyframes"));
if (hasNumInput(&dgo->num)) {
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&dgo->num, str_offs, &dgo->scene->unit);
+ outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 4008ca228ac..72405a51aca 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1816,11 +1816,11 @@ static bool save_image_op(
opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
RNA_boolean_get(op->ptr, "save_as_render"));
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
/* Remember file path for next save. */
BLI_strncpy(G.ima, opts->filepath, sizeof(G.ima));
@@ -3147,6 +3147,23 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
+/* Returns mouse position in image space. */
+bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2])
+{
+ void *lock;
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
+
+ if (ibuf == NULL) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ return false;
+ }
+
+ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(
SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 391c68f4231..feee268c6d3 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -911,6 +911,8 @@ static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
{
+ /* Walk forward over any applied steps of same type,
+ * then walk back in the next loop, un-applying them. */
ImageUndoStep *us_iter = us;
while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
if (us_iter->step.next->is_applied == false) {
@@ -919,7 +921,7 @@ static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
us_iter = (ImageUndoStep *)us_iter->step.next;
}
while (us_iter != us || (!is_final && us_iter == us)) {
-
+ BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
image_undosys_step_decode_undo_impl(us_iter, is_final);
if (us_iter == us) {
break;
@@ -949,6 +951,7 @@ static void image_undosys_step_decode_redo(ImageUndoStep *us)
static void image_undosys_step_decode(
struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
{
+ /* NOTE: behavior for undo/redo closely matches sculpt undo. */
BLI_assert(dir != STEP_INVALID);
ImageUndoStep *us = (ImageUndoStep *)us_p;
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index fb297672f0f..f2cea23af76 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -594,11 +594,11 @@ static int nla_action_unlink_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int nla_action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+static int nla_action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* NOTE: this is hardcoded to match the behavior for the unlink button
* (in interface_templates.c) */
- RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0);
+ RNA_boolean_set(op->ptr, "force_delete", event->shift != 0);
return nla_action_unlink_exec(C, op);
}
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 977c2053187..1354c06305c 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -643,7 +643,8 @@ static void node_buts_image_user(uiLayout *layout,
PointerRNA *ptr,
PointerRNA *imaptr,
PointerRNA *iuserptr,
- bool compositor)
+ const bool show_layer_selection,
+ const bool show_color_management)
{
if (!imaptr->data) {
return;
@@ -677,20 +678,22 @@ static void node_buts_image_user(uiLayout *layout,
uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ if (show_layer_selection && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers")) {
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
- PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
- uiItemL(split, IFACE_("Color Space"), ICON_NONE);
- uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
+ if (show_color_management) {
+ uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
+ PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
+ uiItemL(split, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- /* Avoid losing changes image is painted. */
- if (BKE_image_is_dirty(imaptr->data)) {
- uiLayoutSetEnabled(split, false);
+ /* Avoid losing changes image is painted. */
+ if (BKE_image_is_dirty(imaptr->data)) {
+ uiLayoutSetEnabled(split, false);
+ }
}
}
@@ -756,7 +759,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
*/
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true);
}
static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -785,7 +788,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true);
}
static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1374,7 +1377,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
PointerRNA imaptr = RNA_pointer_get(ptr, "image");
- node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true);
+ node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true, true);
node_buts_image_views(layout, C, ptr, &imaptr);
}
@@ -2665,27 +2668,64 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
-static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
{
uiLayout *col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Matte Objects:"), ICON_NONE);
uiLayout *row = uiLayoutRow(col, true);
- uiTemplateCryptoPicker(row, ptr, "add");
- uiTemplateCryptoPicker(row, ptr, "remove");
+ uiTemplateCryptoPicker(row, ptr, "add", ICON_ADD);
+ uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_cryptomatte_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
+static void node_composit_buts_cryptomatte_legacy_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
{
uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ADD, "NODE_OT_cryptomatte_layer_add");
uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_REMOVE, "NODE_OT_cryptomatte_layer_remove");
}
+static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ uiTemplateID(col, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
+ }
+ else {
+ uiTemplateID(
+ col, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
+
+ NodeCryptomatte *crypto = (NodeCryptomatte *)node->storage;
+ PointerRNA imaptr = RNA_pointer_get(ptr, "image");
+ PointerRNA iuserptr;
+ RNA_pointer_create((ID *)ptr->owner_id, &RNA_ImageUser, &crypto->iuser, &iuserptr);
+ uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
+
+ node_buts_image_user(col, C, ptr, &imaptr, &iuserptr, false, false);
+ node_buts_image_views(col, C, ptr, &imaptr);
+ }
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "layer_name", 0, "", ICON_NONE);
+ uiItemL(col, IFACE_("Matte ID:"), ICON_NONE);
+
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
+ uiTemplateCryptoPicker(row, ptr, "add", ICON_ADD);
+ uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
+}
+
static void node_composit_buts_brightcontrast(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2938,7 +2978,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
- ntype->draw_buttons_ex = node_composit_buts_cryptomatte_ex;
+ break;
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
+ ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
+ ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
case CMP_NODE_BRIGHTCONTRAST:
ntype->draw_buttons = node_composit_buts_brightcontrast;
@@ -3385,7 +3428,12 @@ static void std_node_socket_draw(
}
}
break;
- case SOCK_RGBA:
+ case SOCK_RGBA: {
+ uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
+ uiItemL(row, text, 0);
+ uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ break;
+ }
case SOCK_STRING: {
uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
uiItemL(row, text, 0);
@@ -3588,6 +3636,13 @@ bool node_link_bezier_handles(const View2D *v2d,
if (link->fromsock) {
vec[0][0] = link->fromsock->locx;
vec[0][1] = link->fromsock->locy;
+ if (link->fromsock->flag & SOCK_MULTI_INPUT) {
+ node_link_calculate_multi_input_position(link->fromsock->locx,
+ link->fromsock->locy,
+ link->fromsock->total_inputs - 1,
+ link->fromsock->total_inputs,
+ vec[0]);
+ }
fromreroute = (link->fromnode && link->fromnode->type == NODE_REROUTE);
}
else {
@@ -3601,7 +3656,11 @@ bool node_link_bezier_handles(const View2D *v2d,
vec[3][0] = link->tosock->locx;
vec[3][1] = link->tosock->locy;
if (!(link->tonode->flag & NODE_HIDDEN) && link->tosock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link, vec[3]);
+ node_link_calculate_multi_input_position(link->tosock->locx,
+ link->tosock->locy,
+ link->multi_input_socket_index,
+ link->tosock->total_inputs,
+ vec[3]);
}
toreroute = (link->tonode && link->tonode->type == NODE_REROUTE);
}
@@ -3692,17 +3751,21 @@ bool node_link_bezier_points(const View2D *v2d,
#define LINK_WIDTH (2.5f * UI_DPI_FAC)
#define ARROW_SIZE (7 * UI_DPI_FAC)
+/* Reroute arrow shape and mute bar. These are expanded here and shrunk in the glsl code.
+ * See: gpu_shader_2D_nodelink_vert.glsl */
static float arrow_verts[3][2] = {{-1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f, -1.0f}};
static float arrow_expand_axis[3][2] = {{0.7071f, 0.7071f}, {M_SQRT2, 0.0f}, {0.7071f, -0.7071f}};
+static float mute_verts[3][2] = {{0.7071f, 1.0f}, {0.7071f, 0.0f}, {0.7071f, -1.0f}};
+static float mute_expand_axis[3][2] = {{1.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, -0.0f}};
static struct {
GPUBatch *batch; /* for batching line together */
GPUBatch *batch_single; /* for single line */
GPUVertBuf *inst_vbo;
uint p0_id, p1_id, p2_id, p3_id;
- uint colid_id;
+ uint colid_id, muted_id;
GPUVertBufRaw p0_step, p1_step, p2_step, p3_step;
- GPUVertBufRaw colid_step;
+ GPUVertBufRaw colid_step, muted_step;
uint count;
bool enabled;
} g_batch_link = {0};
@@ -3715,6 +3778,8 @@ static void nodelink_batch_reset(void)
GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p3_id, &g_batch_link.p3_step);
GPU_vertbuf_attr_get_raw_data(
g_batch_link.inst_vbo, g_batch_link.colid_id, &g_batch_link.colid_step);
+ GPU_vertbuf_attr_get_raw_data(
+ g_batch_link.inst_vbo, g_batch_link.muted_id, &g_batch_link.muted_step);
g_batch_link.count = 0;
}
@@ -3742,6 +3807,8 @@ static void nodelink_batch_init(void)
int vcount = LINK_RESOL * 2; /* curve */
vcount += 2; /* restart strip */
vcount += 3 * 2; /* arrow */
+ vcount += 2; /* restart strip */
+ vcount += 3 * 2; /* mute */
vcount *= 2; /* shadow */
vcount += 2; /* restart strip */
GPU_vertbuf_data_alloc(vbo, vcount);
@@ -3785,6 +3852,25 @@ static void nodelink_batch_init(void)
}
/* restart */
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ uv[0] = 127;
+ uv[1] = 0;
+ copy_v2_v2(pos, mute_verts[0]);
+ copy_v2_v2(exp, mute_expand_axis[0]);
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ /* bar */
+ for (int i = 0; i < 3; ++i) {
+ uv[1] = 0;
+ copy_v2_v2(pos, mute_verts[i]);
+ copy_v2_v2(exp, mute_expand_axis[i]);
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ uv[1] = 255;
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ }
+
+ /* restart */
if (k == 0) {
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
}
@@ -3808,6 +3894,8 @@ static void nodelink_batch_init(void)
&format_inst, "P3", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
g_batch_link.colid_id = GPU_vertformat_attr_add(
&format_inst, "colid_doarrow", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ g_batch_link.muted_id = GPU_vertformat_attr_add(
+ &format_inst, "domuted", GPU_COMP_U8, 2, GPU_FETCH_INT);
g_batch_link.inst_vbo = GPU_vertbuf_create_with_format_ex(&format_inst, GPU_USAGE_STREAM);
/* Alloc max count but only draw the range we need. */
GPU_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE);
@@ -3882,12 +3970,13 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
int th_col1,
int th_col2,
int th_col3,
- bool drawarrow)
+ bool drawarrow,
+ bool drawmuted)
{
/* Only allow these colors. If more is needed, you need to modify the shader accordingly. */
BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
- BLI_assert(ELEM(th_col3, TH_WIRE, -1));
+ BLI_assert(ELEM(th_col3, TH_WIRE, TH_REDALERT, -1));
g_batch_link.count++;
copy_v2_v2(GPU_vertbuf_raw_step(&g_batch_link.p0_step), p0);
@@ -3899,6 +3988,8 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
colid[1] = nodelink_get_color_id(th_col2);
colid[2] = nodelink_get_color_id(th_col3);
colid[3] = drawarrow;
+ char *muted = GPU_vertbuf_raw_step(&g_batch_link.muted_step);
+ muted[0] = drawmuted;
if (g_batch_link.count == NODELINK_GROUP_SIZE) {
nodelink_batch_draw(snode);
@@ -3918,7 +4009,7 @@ void node_draw_link_bezier(const View2D *v2d,
if (node_link_bezier_handles(v2d, snode, link, vec)) {
int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
(link->fromnode && (link->fromnode->type == NODE_REROUTE)));
-
+ int drawmuted = (link->flag & NODE_LINK_MUTED);
if (g_batch_link.batch == NULL) {
nodelink_batch_init();
}
@@ -3926,7 +4017,7 @@ void node_draw_link_bezier(const View2D *v2d,
if (g_batch_link.enabled && !highlighted) {
/* Add link to batch. */
nodelink_batch_add_link(
- snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow);
+ snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow, drawmuted);
}
else {
/* Draw single link. */
@@ -3950,6 +4041,7 @@ void node_draw_link_bezier(const View2D *v2d,
GPU_batch_uniform_1f(batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
+ GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
GPU_batch_draw(batch);
}
}
@@ -3982,8 +4074,11 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
if (link->flag & NODE_LINKFLAG_HILITE) {
th_col1 = th_col2 = TH_ACTIVE;
}
+ else if (link->flag & NODE_LINK_MUTED) {
+ th_col1 = th_col2 = TH_REDALERT;
+ }
else {
- /* regular link */
+ /* Regular link, highlight if connected to selected node. */
if (link->fromnode && link->fromnode->flag & SELECT) {
th_col1 = TH_EDGE_SELECT;
}
@@ -3993,7 +4088,8 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
}
}
else {
- th_col1 = th_col2 = TH_REDALERT;
+ /* Invalid link. */
+ th_col1 = th_col2 = th_col3 = TH_REDALERT;
// th_col3 = -1; /* no shadow */
}
}
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index e0de2393917..a646804e0fd 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -23,7 +23,9 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_node_types.h"
+#include "DNA_texture_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -418,6 +420,305 @@ void NODE_OT_add_group(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Add Node Object Operator
+ * \{ */
+
+static Object *node_add_object_get_and_poll_object_node_tree(Main *bmain, wmOperator *op)
+{
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+
+ Object *object = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
+ if (!object) {
+ return NULL;
+ }
+
+ return object;
+}
+
+static int node_add_object_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *ntree = snode->edittree;
+ Object *object;
+
+ if (!(object = node_add_object_get_and_poll_object_node_tree(bmain, op))) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ bNode *object_node = node_add_node(
+ C, NULL, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ if (!object_node) {
+ BKE_report(op->reports, RPT_WARNING, "Could not add node object");
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeSocket *sock = nodeFindSocket(object_node, SOCK_IN, "Object");
+ if (!sock) {
+ BKE_report(op->reports, RPT_WARNING, "Could not find node object socket");
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeSocketValueObject *socket_data = sock->default_value;
+ socket_data->value = object;
+ id_us_plus(&object->id);
+
+ nodeSetActive(ntree, object_node);
+ ntreeUpdateTree(bmain, ntree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+static int node_add_object_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ /* Convert mouse coordinates to v2d space. */
+ UI_view2d_region_to_view(&region->v2d,
+ event->mval[0],
+ event->mval[1],
+ &snode->runtime->cursor[0],
+ &snode->runtime->cursor[1]);
+
+ snode->runtime->cursor[0] /= UI_DPI_FAC;
+ snode->runtime->cursor[1] /= UI_DPI_FAC;
+
+ return node_add_object_exec(C, op);
+}
+
+static bool node_add_object_poll(bContext *C)
+{
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY);
+}
+
+void NODE_OT_add_object(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Node Object";
+ ot->description = "Add an object info node to the current node editor";
+ ot->idname = "NODE_OT_add_object";
+
+ /* callbacks */
+ ot->exec = node_add_object_exec;
+ ot->invoke = node_add_object_invoke;
+ ot->poll = node_add_object_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Node Texture Operator
+ * \{ */
+
+static Tex *node_add_texture_get_and_poll_texture_node_tree(Main *bmain, wmOperator *op)
+{
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+
+ Tex *texture = (Tex *)BKE_libblock_find_name(bmain, ID_TE, name);
+ if (!texture) {
+ return NULL;
+ }
+
+ return texture;
+}
+
+static int node_add_texture_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *ntree = snode->edittree;
+ Tex *texture;
+
+ if (!(texture = node_add_texture_get_and_poll_texture_node_tree(bmain, op))) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ bNode *texture_node = node_add_node(C,
+ NULL,
+ GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE,
+ snode->runtime->cursor[0],
+ snode->runtime->cursor[1]);
+ if (!texture_node) {
+ BKE_report(op->reports, RPT_WARNING, "Could not add texture node");
+ return OPERATOR_CANCELLED;
+ }
+
+ texture_node->id = &texture->id;
+ id_us_plus(&texture->id);
+
+ nodeSetActive(ntree, texture_node);
+ ntreeUpdateTree(bmain, ntree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+static int node_add_texture_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ /* Convert mouse coordinates to v2d space. */
+ UI_view2d_region_to_view(&region->v2d,
+ event->mval[0],
+ event->mval[1],
+ &snode->runtime->cursor[0],
+ &snode->runtime->cursor[1]);
+
+ snode->runtime->cursor[0] /= UI_DPI_FAC;
+ snode->runtime->cursor[1] /= UI_DPI_FAC;
+
+ return node_add_texture_exec(C, op);
+}
+
+static bool node_add_texture_poll(bContext *C)
+{
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY);
+}
+
+void NODE_OT_add_texture(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Node Texture";
+ ot->description = "Add a texture to the current node editor";
+ ot->idname = "NODE_OT_add_texture";
+
+ /* callbacks */
+ ot->exec = node_add_texture_exec;
+ ot->invoke = node_add_texture_invoke;
+ ot->poll = node_add_texture_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(
+ ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Node Collection Operator
+ * \{ */
+
+static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *bmain,
+ wmOperator *op)
+{
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+
+ Collection *collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
+ if (!collection) {
+ return NULL;
+ }
+
+ return collection;
+}
+
+static int node_add_collection_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *ntree = snode->edittree;
+ Collection *collection;
+
+ if (!(collection = node_add_collection_get_and_poll_collection_node_tree(bmain, op))) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ bNode *collection_node = node_add_node(
+ C, NULL, GEO_NODE_COLLECTION_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ if (!collection_node) {
+ BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeSocket *sock = nodeFindSocket(collection_node, SOCK_IN, "Collection");
+ if (!sock) {
+ BKE_report(op->reports, RPT_WARNING, "Could not find node collection socket");
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeSocketValueCollection *socket_data = sock->default_value;
+ socket_data->value = collection;
+ id_us_plus(&collection->id);
+
+ nodeSetActive(ntree, collection_node);
+ ntreeUpdateTree(bmain, ntree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+static int node_add_collection_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ /* Convert mouse coordinates to v2d space. */
+ UI_view2d_region_to_view(&region->v2d,
+ event->mval[0],
+ event->mval[1],
+ &snode->runtime->cursor[0],
+ &snode->runtime->cursor[1]);
+
+ snode->runtime->cursor[0] /= UI_DPI_FAC;
+ snode->runtime->cursor[1] /= UI_DPI_FAC;
+
+ return node_add_collection_exec(C, op);
+}
+
+static bool node_add_collection_poll(bContext *C)
+{
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY);
+}
+
+void NODE_OT_add_collection(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Node Collection";
+ ot->description = "Add an collection info node to the current node editor";
+ ot->idname = "NODE_OT_add_collection";
+
+ /* callbacks */
+ ot->exec = node_add_collection_exec;
+ ot->invoke = node_add_collection_invoke;
+ ot->poll = node_add_collection_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(
+ ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Add File Node Operator
* \{ */
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 162f3878f7e..f64ce771b25 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_map.hh"
#include "BLI_math.h"
+#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
@@ -81,6 +82,7 @@
# include "COM_compositor.h"
#endif
+using blender::Set;
using blender::Span;
using blender::Vector;
@@ -1236,16 +1238,15 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
for (const NodeWarning &warning : warnings.drop_back(1)) {
complete_string += warning.message;
+ /* Adding the period is not ideal for multi-line messages, but it is consistent
+ * with other tooltip implementations in Blender, so it is added here. */
+ complete_string += '.';
complete_string += '\n';
}
+ /* Let the tooltip system automatically add the last period. */
complete_string += warnings.last().message;
- /* Remove the last period-- the tooltip system adds this automatically. */
- if (complete_string.back() == '.') {
- complete_string.pop_back();
- }
-
return BLI_strdupn(complete_string.c_str(), complete_string.size());
}
@@ -1747,10 +1748,11 @@ static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
LISTBASE_FOREACH (struct bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_MULTI_INPUT) {
+ Set<bNodeSocket *> visited_from_sockets;
socket->total_inputs = 0;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (link->tosock == socket) {
- socket->total_inputs++;
+ visited_from_sockets.add(link->fromsock);
}
}
/* Count temporary links going into this socket. */
@@ -1758,10 +1760,11 @@ static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
bNodeLink *link = (bNodeLink *)linkdata->data;
if (link->tosock == socket) {
- socket->total_inputs++;
+ visited_from_sockets.add(link->fromsock);
}
}
}
+ socket->total_inputs = visited_from_sockets.size();
}
}
}
@@ -1781,25 +1784,6 @@ void node_update_nodetree(const bContext *C, bNodeTree *ntree)
}
}
-static bool compare_link_by_angle_to_node(const bNodeLink *link_a, const bNodeLink *link_b)
-{
- BLI_assert(link_a->tosock == link_b->tosock);
- const float socket_location[2] = {link_a->tosock->locx, link_a->tosock->locy};
- const float up_direction[2] = {0.0f, 1.0f};
-
- float delta_a[2] = {link_a->fromsock->locx - socket_location[0],
- link_a->fromsock->locy - socket_location[1]};
- normalize_v2(delta_a);
- const float angle_a = angle_normalized_v2v2(up_direction, delta_a);
-
- float delta_b[2] = {link_b->fromsock->locx - socket_location[0],
- link_b->fromsock->locy - socket_location[1]};
- normalize_v2(delta_b);
- const float angle_b = angle_normalized_v2v2(up_direction, delta_b);
-
- return angle_a > angle_b;
-}
-
static void node_draw(const bContext *C,
ARegion *region,
SpaceNode *snode,
@@ -1814,42 +1798,6 @@ static void node_draw(const bContext *C,
#define USE_DRAW_TOT_UPDATE
-/**
- * Automatically sort the input links to multi-input sockets to avoid crossing noodles.
- */
-static void sort_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
-{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->flag & SOCK_MULTI_INPUT) {
- /* The total is calculated in #node_update_nodetree, which runs before this draw step. */
- const int total_inputs = socket->total_inputs;
- Vector<bNodeLink *> input_links;
- input_links.reserve(total_inputs);
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->tosock == socket) {
- input_links.append(link);
- }
- }
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
- if (link->tosock == socket) {
- input_links.append(link);
- }
- }
- }
-
- std::sort(input_links.begin(), input_links.end(), compare_link_by_angle_to_node);
- for (const int i : input_links.index_range()) {
- input_links[i]->multi_input_socket_index = i;
- }
- }
- }
- }
-}
-
void node_draw_nodetree(const bContext *C,
ARegion *region,
SpaceNode *snode,
@@ -1886,8 +1834,6 @@ void node_draw_nodetree(const bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode);
- sort_multi_input_socket_links(ntree, snode);
-
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (!nodeLinkIsHidden(link)) {
node_draw_link(&region->v2d, snode, link);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 4826b6c72ba..b72a6503749 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -107,14 +107,15 @@ float node_socket_calculate_height(const bNodeSocket *socket)
return sock_height;
}
-void node_link_calculate_multi_input_position(const bNodeLink *link, float r[2])
+void node_link_calculate_multi_input_position(const float socket_x,
+ const float socket_y,
+ const int index,
+ const int total_inputs,
+ float r[2])
{
- float offset = (link->tosock->total_inputs * NODE_MULTI_INPUT_LINK_GAP -
- NODE_MULTI_INPUT_LINK_GAP) *
- 0.5;
- r[0] = link->tosock->locx - NODE_SOCKSIZE * 0.5f;
- r[1] = link->tosock->locy - offset +
- (link->multi_input_socket_index * NODE_MULTI_INPUT_LINK_GAP);
+ float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) * 0.5;
+ r[0] = socket_x - NODE_SOCKSIZE * 0.5f;
+ r[1] = socket_y - offset + (index * NODE_MULTI_INPUT_LINK_GAP);
}
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
@@ -1403,8 +1404,12 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (node->type == CMP_NODE_R_LAYERS) {
+ if ((node->type == CMP_NODE_R_LAYERS) ||
+ (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) {
ID *id = node->id;
+ if (id == NULL) {
+ continue;
+ }
if (id->tag & LIB_TAG_DOIT) {
RE_ReadRenderResult(curscene, (Scene *)id);
ntreeCompositTagRender((Scene *)id);
@@ -2231,10 +2236,13 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
link->tosock->new_sock);
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ Main *bmain = CTX_data_main(C);
+ ntreeUpdateTree(bmain, snode->edittree);
snode_notify(C, snode);
snode_dag_update(C, snode);
+ /* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
+ DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
}
@@ -2738,7 +2746,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
node = nodeGetActive(snode->edittree);
}
- if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
return OPERATOR_CANCELLED;
}
@@ -2782,7 +2790,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
node = nodeGetActive(snode->edittree);
}
- if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 41f04dad221..6d0cd254505 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -37,6 +37,7 @@
using blender::IndexRange;
using blender::Map;
+using blender::MultiValueMap;
using blender::Set;
using blender::StringRef;
@@ -62,30 +63,31 @@ static void attribute_search_update_fn(
return;
}
- const Set<std::string> &attribute_name_hints = ui_storage->attribute_name_hints;
+ const MultiValueMap<std::string, AvailableAttributeInfo> &attribute_hints =
+ ui_storage->attribute_hints;
- if (str[0] != '\0' && !attribute_name_hints.contains_as(StringRef(str))) {
+ if (str[0] != '\0' && attribute_hints.lookup_as(StringRef(str)).is_empty()) {
/* Any string may be valid, so add the current search string with the hints. */
UI_search_item_add(items, str, (void *)str, ICON_ADD, 0, 0);
}
- /* Skip the filter when the menu is first opened, so all of the items are visible. */
- if (is_first) {
- for (const std::string &attribute_name : attribute_name_hints) {
- /* Just use the pointer to the name string as the search data,
- * since it's not used anyway but we need a pointer. */
- UI_search_item_add(items, attribute_name.c_str(), (void *)&attribute_name, ICON_NONE, 0, 0);
- }
- return;
+ if (str[0] == '\0' && !is_first) {
+ /* Allow clearing the text field when the string is empty, but not on the first pass,
+ * or opening an attribute field for the first time would show this search item. */
+ UI_search_item_add(items, str, (void *)str, ICON_X, 0, 0);
}
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str;
+
StringSearch *search = BLI_string_search_new();
- for (const std::string &attribute_name : attribute_name_hints) {
+ for (const std::string &attribute_name : attribute_hints.keys()) {
BLI_string_search_add(search, attribute_name.c_str(), (void *)&attribute_name);
}
std::string **filtered_items;
- const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
for (const int i : IndexRange(filtered_amount)) {
std::string *item = filtered_items[i];
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index b3ae336aadf..e1de4bfc21e 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -1030,6 +1030,9 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, gnode);
if (ngroup) {
ED_node_tree_push(snode, ngroup, gnode);
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ sort_multi_input_socket_links(snode, node, NULL, NULL);
+ }
ntreeUpdateTree(bmain, ngroup);
}
}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 972e6cab123..21a36ff9683 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -38,11 +38,9 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
-struct uiBut;
struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
-struct uiBlock;
#ifdef __cplusplus
extern "C" {
@@ -59,6 +57,11 @@ typedef struct bNodeLinkDrag {
ListBase links;
bool from_multi_input_socket;
int in_out;
+
+ /** Temporarily stores the last picked link from multi input socket operator. */
+ struct bNodeLink *last_picked_multi_input_socket_link;
+
+ struct bNode *last_node_hovered_while_dragging_a_link;
} bNodeLinkDrag;
typedef struct SpaceNode_Runtime {
@@ -85,7 +88,11 @@ void space_node_group_offset(struct SpaceNode *snode, float *x, float *y);
/* node_draw.cc */
float node_socket_calculate_height(const bNodeSocket *socket);
-void node_link_calculate_multi_input_position(const bNodeLink *link, float r[2]);
+void node_link_calculate_multi_input_position(const float socket_x,
+ const float socket_y,
+ const int index,
+ const int total_inputs,
+ float r[2]);
int node_get_colorid(struct bNode *node);
int node_get_resize_cursor(int directions);
@@ -201,6 +208,9 @@ bNode *node_add_node(
const struct bContext *C, const char *idname, int type, float locx, float locy);
void NODE_OT_add_reroute(struct wmOperatorType *ot);
void NODE_OT_add_group(struct wmOperatorType *ot);
+void NODE_OT_add_object(struct wmOperatorType *ot);
+void NODE_OT_add_collection(struct wmOperatorType *ot);
+void NODE_OT_add_texture(struct wmOperatorType *ot);
void NODE_OT_add_file(struct wmOperatorType *ot);
void NODE_OT_add_mask(struct wmOperatorType *ot);
void NODE_OT_new_node_tree(struct wmOperatorType *ot);
@@ -214,12 +224,17 @@ void NODE_OT_group_separate(struct wmOperatorType *ot);
void NODE_OT_group_edit(struct wmOperatorType *ot);
/* node_relationships.c */
+void sort_multi_input_socket_links(struct SpaceNode *snode,
+ struct bNode *node,
+ struct bNodeLink *drag_link,
+ float cursor[2]);
bool node_connected_to_output(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
void NODE_OT_link(struct wmOperatorType *ot);
void NODE_OT_link_make(struct wmOperatorType *ot);
void NODE_OT_links_cut(struct wmOperatorType *ot);
void NODE_OT_links_detach(struct wmOperatorType *ot);
+void NODE_OT_links_mute(struct wmOperatorType *ot);
void NODE_OT_parent_set(struct wmOperatorType *ot);
void NODE_OT_join(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 7671547363b..e35b444aa11 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -68,6 +68,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_link_make);
WM_operatortype_append(NODE_OT_links_cut);
WM_operatortype_append(NODE_OT_links_detach);
+ WM_operatortype_append(NODE_OT_links_mute);
WM_operatortype_append(NODE_OT_add_reroute);
WM_operatortype_append(NODE_OT_group_make);
@@ -89,6 +90,9 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_backimage_sample);
WM_operatortype_append(NODE_OT_add_group);
+ WM_operatortype_append(NODE_OT_add_object);
+ WM_operatortype_append(NODE_OT_add_collection);
+ WM_operatortype_append(NODE_OT_add_texture);
WM_operatortype_append(NODE_OT_add_file);
WM_operatortype_append(NODE_OT_add_mask);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index d6edfcce8e8..2cc44d72c72 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -280,7 +280,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
float distance = dist_squared_to_line_segment_v2(cursor, l1, l2);
if (distance < cursor_link_touch_distance) {
link_to_pick = link;
- RNA_int_set(op->ptr, "last_picked_link_index", link->multi_input_socket_index);
+ nldrag->last_picked_multi_input_socket_link = link_to_pick;
}
}
}
@@ -290,13 +290,9 @@ static void pick_input_link_by_link_intersect(const bContext *C,
* Not essential for the basic behavior, but can make interaction feel a bit better if
* the mouse moves to the right and loses the "selection." */
if (!link_to_pick) {
- int last_picked_link_index = RNA_int_get(op->ptr, "last_picked_link_index");
- if (last_picked_link_index > -1) {
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (link->multi_input_socket_index == last_picked_link_index) {
- link_to_pick = link;
- }
- }
+ bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link;
+ if (last_picked_link) {
+ link_to_pick = last_picked_link;
}
}
@@ -438,6 +434,75 @@ static bool snode_autoconnect_input(SpaceNode *snode,
return true;
}
+typedef struct LinkAndPosition {
+ struct bNodeLink *link;
+ float multi_socket_position[2];
+} LinkAndPosition;
+
+static int compare_link_by_y_position(const void *a, const void *b)
+{
+ const LinkAndPosition *link_and_position_a = *(const LinkAndPosition **)a;
+ const LinkAndPosition *link_and_position_b = *(const LinkAndPosition **)b;
+
+ BLI_assert(link_and_position_a->link->tosock == link_and_position_b->link->tosock);
+ const float link_a_y = link_and_position_a->multi_socket_position[1];
+ const float link_b_y = link_and_position_b->multi_socket_position[1];
+ return link_a_y > link_b_y ? 1 : -1;
+}
+
+void sort_multi_input_socket_links(SpaceNode *snode,
+ bNode *node,
+ bNodeLink *drag_link,
+ float cursor[2])
+{
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (!(socket->flag & SOCK_MULTI_INPUT)) {
+ continue;
+ }
+ /* The total is calculated in #node_update_nodetree, which runs before this draw step. */
+ int total_inputs = socket->total_inputs + 1;
+ struct LinkAndPosition **input_links = MEM_malloc_arrayN(
+ total_inputs, sizeof(LinkAndPosition *), __func__);
+
+ int index = 0;
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (link->tosock == socket) {
+ struct LinkAndPosition *link_and_position = MEM_callocN(sizeof(struct LinkAndPosition),
+ __func__);
+ link_and_position->link = link;
+ node_link_calculate_multi_input_position(link->tosock->locx,
+ link->tosock->locy,
+ link->multi_input_socket_index,
+ link->tosock->total_inputs,
+ link_and_position->multi_socket_position);
+ input_links[index] = link_and_position;
+ index++;
+ }
+ }
+
+ if (drag_link) {
+ LinkAndPosition *link_and_position = MEM_callocN(sizeof(LinkAndPosition), __func__);
+ link_and_position->link = drag_link;
+ copy_v2_v2(link_and_position->multi_socket_position, cursor);
+ input_links[index] = link_and_position;
+ index++;
+ }
+
+ qsort(input_links, index, sizeof(bNodeLink *), compare_link_by_y_position);
+
+ for (int i = 0; i < index; i++) {
+ input_links[i]->link->multi_input_socket_index = i;
+ }
+
+ for (int i = 0; i < index; i++) {
+ if (input_links[i]) {
+ MEM_freeN(input_links[i]);
+ }
+ }
+ MEM_freeN(input_links);
+ }
+}
+
static void snode_autoconnect(Main *bmain,
SpaceNode *snode,
const bool allow_multiple,
@@ -820,24 +885,39 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
bNodeLink *link = linkdata->data;
- /* skip if this is already the target socket */
- if (link->tosock == tsock) {
- continue;
- }
/* skip if socket is on the same node as the fromsock */
if (tnode && link->fromnode == tnode) {
continue;
}
+ /* Skip if tsock is already linked with this output. */
+ bNodeLink *existing_link_connected_to_fromsock = NULL;
+ LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) {
+ if (existing_link->fromsock == link->fromsock && existing_link->tosock == tsock) {
+ existing_link_connected_to_fromsock = existing_link;
+ break;
+ }
+ }
+
/* attach links to the socket */
link->tonode = tnode;
link->tosock = tsock;
+ nldrag->last_node_hovered_while_dragging_a_link = tnode;
+ if (existing_link_connected_to_fromsock) {
+ link->multi_input_socket_index =
+ existing_link_connected_to_fromsock->multi_input_socket_index;
+ continue;
+ }
+ sort_multi_input_socket_links(snode, tnode, link, cursor);
}
}
else {
LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
bNodeLink *link = linkdata->data;
-
+ if (nldrag->last_node_hovered_while_dragging_a_link) {
+ sort_multi_input_socket_links(
+ snode, nldrag->last_node_hovered_while_dragging_a_link, NULL, cursor);
+ }
link->tonode = NULL;
link->tosock = NULL;
}
@@ -1032,7 +1112,6 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float cursor[2];
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
RNA_float_set_array(op->ptr, "drag_start", cursor);
- RNA_int_set(op->ptr, "last_picked_link_index", -1);
RNA_boolean_set(op->ptr, "has_link_picked", false);
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
@@ -1102,15 +1181,6 @@ void NODE_OT_link(wmOperatorType *ot)
-UI_PRECISION_FLOAT_MAX,
UI_PRECISION_FLOAT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_int(ot->srna,
- "last_picked_link_index",
- -1,
- -1,
- 4095,
- "Last Picked Link Index",
- "The index of the last picked link on a multi-input socket",
- -1,
- 4095);
RNA_def_property_flag(prop, PROP_HIDDEN);
}
@@ -1157,8 +1227,8 @@ void NODE_OT_link_make(wmOperatorType *ot)
ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
}
-/* ********************** Cut Link operator ***************** */
-static bool cut_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
+/* ********************** Node Link Intersect ***************** */
+static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
{
float coord_array[NODE_LINK_RESOL + 1][2];
@@ -1174,6 +1244,7 @@ static bool cut_links_intersect(bNodeLink *link, const float mcoords[][2], int t
return 0;
}
+/* ********************** Cut Link operator ***************** */
static int cut_links_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1206,7 +1277,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
continue;
}
- if (cut_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(link, mcoords, i)) {
if (found == false) {
/* TODO(sergey): Why did we kill jobs twice? */
@@ -1265,6 +1336,110 @@ void NODE_OT_links_cut(wmOperatorType *ot)
RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
+/* ********************** Mute links operator ***************** */
+
+static int mute_links_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ ARegion *region = CTX_wm_region(C);
+ bool do_tag_update = false;
+
+ int i = 0;
+ float mcoords[256][2];
+ RNA_BEGIN (op->ptr, itemptr, "path") {
+ float loc[2];
+
+ RNA_float_get_array(&itemptr, "loc", loc);
+ UI_view2d_region_to_view(
+ &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ i++;
+ if (i >= 256) {
+ break;
+ }
+ }
+ RNA_END;
+
+ if (i > 1) {
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+
+ /* Count intersected links and clear test flag. */
+ int tot = 0;
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (nodeLinkIsHidden(link)) {
+ continue;
+ }
+ link->flag &= ~NODE_LINK_TEST;
+ if (node_links_intersect(link, mcoords, i)) {
+ tot++;
+ }
+ }
+ if (tot == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Mute links. */
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (nodeLinkIsHidden(link) || (link->flag & NODE_LINK_TEST)) {
+ continue;
+ }
+
+ if (node_links_intersect(link, mcoords, i)) {
+ do_tag_update |= (do_tag_update ||
+ node_connected_to_output(bmain, snode->edittree, link->tonode));
+
+ snode_update(snode, link->tonode);
+ nodeMuteLinkToggle(snode->edittree, link);
+ }
+ }
+
+ /* Clear remaining test flags. */
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (nodeLinkIsHidden(link)) {
+ continue;
+ }
+ link->flag &= ~NODE_LINK_TEST;
+ }
+
+ do_tag_update |= ED_node_is_geometry(snode);
+
+ ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ snode_notify(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+}
+
+void NODE_OT_links_mute(wmOperatorType *ot)
+{
+ ot->name = "Mute Links";
+ ot->idname = "NODE_OT_links_mute";
+ ot->description = "Use the mouse to mute links";
+
+ ot->invoke = WM_gesture_lines_invoke;
+ ot->modal = WM_gesture_lines_modal;
+ ot->exec = mute_links_exec;
+ ot->cancel = WM_gesture_lines_cancel;
+
+ ot->poll = ED_operator_node_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* internal */
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_MUTE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+}
+
/* ********************** Detach links operator ***************** */
static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2104,6 +2279,8 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
snode_update(snode, select);
ED_node_tag_update_id((ID *)snode->edittree);
ED_node_tag_update_id(snode->id);
+
+ sort_multi_input_socket_links(snode, node, NULL, NULL);
}
}
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index f0e3f5442cc..3873985d93a 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -330,6 +330,10 @@ static void ui_node_link_items(NodeLinkArg *arg,
int i;
for (ngroup = arg->bmain->nodetrees.first; ngroup; ngroup = ngroup->id.next) {
+ if ((ngroup->type != arg->ntree->type) || !nodeGroupPoll(arg->ntree, ngroup)) {
+ continue;
+ }
+
ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
totitems += BLI_listbase_count(lb);
}
@@ -339,6 +343,10 @@ static void ui_node_link_items(NodeLinkArg *arg,
i = 0;
for (ngroup = arg->bmain->nodetrees.first; ngroup; ngroup = ngroup->id.next) {
+ if ((ngroup->type != arg->ntree->type) || !nodeGroupPoll(arg->ntree, ngroup)) {
+ continue;
+ }
+
ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
bNodeSocket *stemp;
int index;
@@ -826,11 +834,22 @@ static void ui_node_draw_input(
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_RGBA:
- case SOCK_STRING:
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
uiItemDecoratorR(
split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
break;
+ case SOCK_STRING: {
+ const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id;
+ if (node_tree->type == NTREE_GEOMETRY) {
+ node_geometry_add_attribute_search_button(node_tree, node, &inputptr, row);
+ }
+ else {
+ uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
+ }
+ uiItemDecoratorR(
+ split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
+ break;
+ }
default:
add_dummy_decorator = true;
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 8f1dc3c8c3e..8ecab92aa26 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -443,6 +443,32 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
+/* Returns mouse position in image space. */
+bool ED_space_node_get_position(
+ Main *bmain, SpaceNode *snode, struct ARegion *ar, const int mval[2], float fpos[2])
+{
+ if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ 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) {
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return false;
+ }
+
+ /* map the mouse coords to the backdrop image space */
+ float bufx = ibuf->x * snode->zoom;
+ float bufy = ibuf->y * snode->zoom;
+ fpos[0] = (bufx > 0.0f ? ((float)mval[0] - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
+ fpos[1] = (bufy > 0.0f ? ((float)mval[1] - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_image_color_sample().
* And here we've got recursion in the comments tips...
*/
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 289b7d9efa1..5d14919502e 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -667,6 +667,30 @@ static bool node_group_drop_poll(bContext *UNUSED(C),
return WM_drag_is_ID_type(drag, ID_NT);
}
+static bool node_object_drop_poll(bContext *UNUSED(C),
+ wmDrag *drag,
+ const wmEvent *UNUSED(event),
+ const char **UNUSED(r_tooltip))
+{
+ return WM_drag_is_ID_type(drag, ID_OB);
+}
+
+static bool node_collection_drop_poll(bContext *UNUSED(C),
+ wmDrag *drag,
+ const wmEvent *UNUSED(event),
+ const char **UNUSED(r_tooltip))
+{
+ return WM_drag_is_ID_type(drag, ID_GR);
+}
+
+static bool node_texture_drop_poll(bContext *UNUSED(C),
+ wmDrag *drag,
+ const wmEvent *UNUSED(event),
+ const char **UNUSED(r_tooltip))
+{
+ return WM_drag_is_ID_type(drag, ID_TE);
+}
+
static bool node_ima_drop_poll(bContext *UNUSED(C),
wmDrag *drag,
const wmEvent *UNUSED(event),
@@ -721,6 +745,21 @@ static void node_dropboxes(void)
ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
WM_dropbox_add(lb,
+ "NODE_OT_add_object",
+ node_object_drop_poll,
+ node_id_drop_copy,
+ WM_drag_free_imported_drag_ID);
+ WM_dropbox_add(lb,
+ "NODE_OT_add_collection",
+ node_collection_drop_poll,
+ node_id_drop_copy,
+ WM_drag_free_imported_drag_ID);
+ WM_dropbox_add(lb,
+ "NODE_OT_add_texture",
+ node_texture_drop_poll,
+ node_id_drop_copy,
+ WM_drag_free_imported_drag_ID);
+ WM_dropbox_add(lb,
"NODE_OT_add_group",
node_group_drop_poll,
node_group_drop_copy,
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index d54265aa292..4a1e5c1a12c 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -56,8 +56,16 @@ set(SRC
tree/tree_display_view_layer.cc
tree/tree_element.cc
tree/tree_element_anim_data.cc
- tree/tree_element_driver_base.cc
+ tree/tree_element_collection.cc
+ tree/tree_element_driver.cc
+ tree/tree_element_gpencil_layer.cc
+ tree/tree_element_id.cc
+ tree/tree_element_id_library.cc
+ tree/tree_element_id_scene.cc
tree/tree_element_nla.cc
+ tree/tree_element_overrides.cc
+ tree/tree_element_scene_objects.cc
+ tree/tree_element_view_layer.cc
outliner_intern.h
tree/tree_display.h
@@ -65,8 +73,16 @@ set(SRC
tree/tree_element.h
tree/tree_element.hh
tree/tree_element_anim_data.hh
- tree/tree_element_driver_base.hh
+ tree/tree_element_collection.hh
+ tree/tree_element_driver.hh
+ tree/tree_element_gpencil_layer.hh
+ tree/tree_element_id.hh
+ tree/tree_element_id_library.hh
+ tree/tree_element_id_scene.hh
tree/tree_element_nla.hh
+ tree/tree_element_overrides.hh
+ tree/tree_element_scene_objects.hh
+ tree/tree_element_view_layer.hh
)
set(LIB
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index ef5733fe375..062d2e2b5d1 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -49,8 +49,6 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "UI_resources.h"
-
#include "outliner_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -71,7 +69,7 @@ bool outliner_is_collection_tree_element(const TreeElement *te)
TSE_VIEW_COLLECTION_BASE)) {
return true;
}
- if (tselem->type == 0 && te->idcode == ID_GR) {
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_GR) {
return true;
}
@@ -94,7 +92,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
Scene *scene = (Scene *)tselem->id;
return scene->master_collection;
}
- if (tselem->type == 0 && te->idcode == ID_GR) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_GR)) {
return (Collection *)tselem->id;
}
@@ -111,7 +109,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu
return TRAVERSE_CONTINUE;
}
- if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id && GS(tselem->id->name) != ID_GR)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -127,7 +125,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
return TRAVERSE_CONTINUE;
}
- if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -1458,7 +1456,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void
BLI_gset_add(data->collections_to_edit, lc);
}
}
- else if (tselem->type == 0 && te->idcode == ID_OB) {
+ else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
Base *base = BKE_view_layer_base_find(data->view_layer, ob);
BLI_gset_add(data->bases_to_edit, base);
diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c
index e2b3b79e027..4293d8da73e 100644
--- a/source/blender/editors/space_outliner/outliner_context.c
+++ b/source/blender/editors/space_outliner/outliner_context.c
@@ -34,7 +34,7 @@ static void outliner_context_selected_ids_recursive(const ListBase *subtree,
{
LISTBASE_FOREACH (const TreeElement *, te, subtree) {
const TreeStoreElem *tse = TREESTORE(te);
- if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) {
+ if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) {
CTX_data_id_list_add(result, tse->id);
}
outliner_context_selected_ids_recursive(&te->subtree, result);
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 3090cab75ae..b3b36811411 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -26,28 +26,21 @@
#include "MEM_guardedalloc.h"
#include "DNA_collection_types.h"
-#include "DNA_constraint_types.h"
#include "DNA_material_types.h"
-#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "BLI_listbase.h"
-#include "BLI_string.h"
#include "BLT_translation.h"
#include "BKE_collection.h"
-#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_layer.h"
-#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
-#include "BKE_shader_fx.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -57,12 +50,9 @@
#include "ED_screen.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "UI_view2d.h"
#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -124,7 +114,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode
TreeElement *te = outliner_drop_find(C, event);
TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
- if (te && te->idcode == idcode && tselem->type == 0) {
+ if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) {
return tselem->id;
}
return NULL;
@@ -215,7 +205,7 @@ static bool is_collection_element(TreeElement *te)
static bool is_object_element(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- return tselem->type == 0 && te->idcode == ID_OB;
+ return (tselem->type == TSE_SOME_ID) && te->idcode == ID_OB;
}
static bool is_pchan_element(TreeElement *te)
@@ -281,7 +271,7 @@ static int outliner_get_insert_index(TreeElement *drag_te,
static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
{
TreeStoreElem *tselem = TREESTORE(te);
- if (te->idcode != ID_OB || tselem->type != 0) {
+ if ((te->idcode != ID_OB) || (tselem->type != TSE_SOME_ID)) {
return false;
}
@@ -421,7 +411,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
TreeElement *te = outliner_drop_find(C, event);
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
- if (!(te && te->idcode == ID_OB && tselem->type == 0)) {
+ if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) {
return OPERATOR_CANCELLED;
}
@@ -647,7 +637,7 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
BKE_object_material_assign(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 008ae727947..278162c4338 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -21,7 +21,6 @@
* \ingroup spoutliner
*/
-#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
@@ -45,7 +44,6 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
@@ -56,14 +54,11 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
-#include "ED_keyframing.h"
-#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -138,13 +133,11 @@ static bool is_object_data_in_editmode(const ID *id, const Object *obact)
/* ****************************************************** */
-static void restrictbutton_recursive_ebone(bContext *C,
+static void restrictbutton_recursive_ebone(bArmature *arm,
EditBone *ebone_parent,
int flag,
bool set_flag)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
EditBone *ebone;
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
@@ -203,8 +196,9 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
-static void restrictbutton_ebone_select_fn(bContext *C, void *UNUSED(poin), void *poin2)
+static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
{
+ bArmature *arm = (bArmature *)poin;
EditBone *ebone = (EditBone *)poin2;
if (ebone->flag & BONE_UNSELECTABLE) {
@@ -213,21 +207,22 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *UNUSED(poin), void
if (CTX_wm_window(C)->eventstate->shift) {
restrictbutton_recursive_ebone(
- C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
+ arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
}
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
-static void restrictbutton_ebone_visibility_fn(bContext *C, void *UNUSED(poin), void *poin2)
+static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
{
+ bArmature *arm = (bArmature *)poin;
EditBone *ebone = (EditBone *)poin2;
if (ebone->flag & BONE_HIDDEN_A) {
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
if (CTX_wm_window(C)->eventstate->shift) {
- restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
+ restrictbutton_recursive_ebone(arm, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
}
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
@@ -668,14 +663,13 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
{
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- Object *obedit = CTX_data_edit_object(C);
BLI_mempool *ts = space_outliner->treestore;
TreeStoreElem *tselem = tsep;
if (ts && tselem) {
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
BLI_libblock_ensure_unique_name(bmain, tselem->id->name);
switch (GS(tselem->id->name)) {
@@ -745,7 +739,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, ebone->name, sizeof(ebone->name));
BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
- ED_armature_bone_rename(bmain, obedit->data, oldname, newname);
+ ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
break;
@@ -1100,11 +1094,11 @@ static void outliner_draw_restrictbuts(uiBlock *block,
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
}
- else if ((tselem->type == 0 && te->idcode == ID_OB) &&
+ else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) &&
(te->flag & TE_CHILD_NOT_IN_COLLECTION)) {
/* Don't show restrict columns for children that are not directly inside the collection. */
}
- else if (tselem->type == 0 && te->idcode == ID_OB) {
+ else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
PointerRNA ptr;
Object *ob = (Object *)tselem->id;
RNA_id_pointer_create(&ob->id, &ptr);
@@ -1352,6 +1346,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
}
else if (tselem->type == TSE_EBONE) {
+ bArmature *arm = (bArmature *)tselem->id;
EditBone *ebone = (EditBone *)te->directdata;
if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
@@ -1371,7 +1366,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
TIP_("Restrict visibility in the 3D View\n"
"* Shift to set children"));
- UI_but_func_set(bt, restrictbutton_ebone_visibility_fn, NULL, ebone);
+ UI_but_func_set(bt, restrictbutton_ebone_visibility_fn, arm, ebone);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1393,7 +1388,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
TIP_("Restrict selection in the 3D View\n"
"* Shift to set children"));
- UI_but_func_set(bt, restrictbutton_ebone_select_fn, NULL, ebone);
+ UI_but_func_set(bt, restrictbutton_ebone_select_fn, arm, ebone);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1699,7 +1694,7 @@ static void outliner_draw_userbuts(uiBlock *block,
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
uiBut *bt;
ID *id = tselem->id;
const char *tip = NULL;
@@ -1949,7 +1944,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
TreeStoreElem *tselem,
const bool lock_object_modes)
{
- if (tselem->type != 0 || te->idcode != ID_OB) {
+ if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
return;
}
@@ -2046,7 +2041,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
{
TreeElementIcon data = {0};
- if (tselem->type) {
+ if (tselem->type != TSE_SOME_ID) {
switch (tselem->type) {
case TSE_ANIM_DATA:
data.icon = ICON_ANIM_DATA; /* XXX */
@@ -2825,7 +2820,8 @@ int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- const int id_index = tselem->type == 0 ? BKE_idtype_idcode_to_index(te->idcode) : INDEX_ID_GR;
+ const int id_index = (tselem->type == TSE_SOME_ID) ? BKE_idtype_idcode_to_index(te->idcode) :
+ INDEX_ID_GR;
if (id_index < INDEX_ID_OB) {
return id_index;
}
@@ -2862,9 +2858,9 @@ static void outliner_draw_iconrow(bContext *C,
te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
/* object hierarchy always, further constrained on level */
- if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) {
+ if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
/* active blocks get white circle */
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
}
@@ -2879,7 +2875,7 @@ static void outliner_draw_iconrow(bContext *C,
active = tree_element_type_active_state_get(C, tvc, te, tselem);
}
- if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) {
+ if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) {
outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
}
else {
@@ -2954,7 +2950,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem)
{
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
switch (te->idcode) {
case ID_OB: {
const Object *ob = (const Object *)tselem->id;
@@ -3023,7 +3019,7 @@ static void outliner_draw_tree_element(bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
/* Colors for active/selected data. */
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
@@ -3080,7 +3076,7 @@ static void outliner_draw_tree_element(bContext *C,
if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
/* Scene collection in view layer can't expand/collapse. */
}
- else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) ||
+ else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) ||
(te->flag & TE_LAZY_CLOSED)) {
/* Open/close icon, only when sub-levels, except for scene. */
int icon_x = startx;
@@ -3117,7 +3113,7 @@ static void outliner_draw_tree_element(bContext *C,
offsx += 2 * ufac;
}
- if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) ||
+ if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) ||
((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) {
const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
if (lib_icon != ICON_NONE) {
@@ -3143,7 +3139,7 @@ static void outliner_draw_tree_element(bContext *C,
/* Closed item, we draw the icons, not when it's a scene, or master-server list though. */
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (te->subtree.first) {
- if (tselem->type == 0 && te->idcode == ID_SCE) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
/* Pass. */
}
/* this tree element always has same amount of branches, so don't draw */
@@ -3210,7 +3206,7 @@ static bool subtree_contains_object(ListBase *lb)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
return true;
}
}
@@ -3265,7 +3261,7 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos,
y = *starty;
}
- else if (tselem->type == 0 && te->idcode == ID_OB) {
+ else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
if (subtree_contains_object(&te->subtree)) {
draw_hierarchy_line = true;
is_object_line = true;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index d1260f02c67..5501e52d69b 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -28,7 +28,6 @@
#include "DNA_ID.h"
#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
-#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -43,27 +42,19 @@
#include "BKE_appdir.h"
#include "BKE_armature.h"
#include "BKE_blender_copybuffer.h"
-#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
-#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "../blenloader/BLO_readfile.h"
-
#include "ED_keyframing.h"
-#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
@@ -72,7 +63,6 @@
#include "WM_types.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "UI_view2d.h"
#include "RNA_access.h"
@@ -464,7 +454,8 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
ID *id = tselem->id;
BLI_assert(id != NULL);
- BLI_assert(ELEM(tselem->type, 0 && te->idcode != 0, TSE_LAYER_COLLECTION));
+ BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
+ (tselem->type == TSE_LAYER_COLLECTION));
UNUSED_VARS_NDEBUG(te);
if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
@@ -638,7 +629,7 @@ static bool outliner_id_remap_find_tree_element(bContext *C,
if (y > te->ys && y < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && tselem->id) {
+ if ((tselem->type == TSE_SOME_ID) && tselem->id) {
printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
@@ -763,7 +754,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree)
TreeStoreElem *tselem = TREESTORE(te);
/* if item is selected and is an ID, tag it as needing to be copied. */
- if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
+ if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
ID *id = tselem->id;
if (!(id->tag & LIB_TAG_DOIT)) {
BKE_copybuffer_tag_ID(tselem->id);
@@ -1640,7 +1631,7 @@ static int subtree_has_objects(ListBase *lb)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
return 1;
}
if (subtree_has_objects(&te->subtree)) {
@@ -1658,7 +1649,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli
TreeStoreElem *tselem = TREESTORE(te);
if (ELEM(tselem->type,
- 0,
+ TSE_SOME_ID,
TSE_SCENE_OBJECTS_BASE,
TSE_VIEW_COLLECTION_BASE,
TSE_LAYER_COLLECTION)) {
@@ -2267,7 +2258,7 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C)
/** \} */
-static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
int num_tagged[INDEX_ID_MAX] = {0};
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index e31af48ab7e..50f089f894a 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -27,17 +27,13 @@
#include "DNA_armature_types.h"
#include "DNA_collection_types.h"
-#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_light_types.h"
-#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
-#include "DNA_world_types.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -52,19 +48,15 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
-#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_shader_fx.h"
-#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_buttons.h"
-#include "ED_gpencil.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -76,7 +68,6 @@
#include "SEQ_sequencer.h"
#include "WM_api.h"
-#include "WM_toolsystem.h"
#include "WM_types.h"
#include "UI_interface.h"
@@ -198,7 +189,7 @@ void outliner_item_mode_toggle(bContext *C,
{
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
@@ -301,7 +292,7 @@ static void tree_element_object_activate(bContext *C,
Object *ob = NULL;
/* if id is not object, we search back */
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
ob = (Object *)tselem->id;
}
else {
@@ -443,7 +434,7 @@ static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *
TreeElement *tep = te->parent;
if (tep) {
TreeStoreElem *tselem = TREESTORE(tep);
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
sce = (Scene *)tselem->id;
}
}
@@ -1165,7 +1156,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
int context = 0;
/* ID Types */
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
RNA_id_pointer_create(tselem->id, &ptr);
switch (te->idcode) {
@@ -1374,12 +1365,12 @@ static void do_outliner_item_activate_tree_element(bContext *C,
tvc->scene,
tvc->view_layer,
te,
- (extend && tselem->type == 0) ? OL_SETSEL_EXTEND :
- OL_SETSEL_NORMAL,
- recursive && tselem->type == 0);
+ (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND :
+ OL_SETSEL_NORMAL,
+ recursive && tselem->type == TSE_SOME_ID);
}
- if (tselem->type == 0) { /* The lib blocks. */
+ if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */
if (do_activate_data == false) {
/* Only select in outliner. */
}
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index 8bd5e3a130a..6543a909a41 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -326,7 +326,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
if (sync_types->object) {
outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects);
}
@@ -503,7 +503,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
if (sync_types->object) {
outliner_select_sync_from_object(view_layer, active_data->object, te, tselem);
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index b735064cfef..052ef9a5dea 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -106,7 +106,7 @@ static void get_element_operation_type(
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
/* Layer collection points to collection ID. */
- if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
+ if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
if (*datalevel == 0) {
*datalevel = tselem->type;
}
@@ -402,7 +402,8 @@ static void outliner_do_libdata_operation(bContext *C,
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
- if ((tselem->type == 0 && te->idcode != 0) || tselem->type == TSE_LAYER_COLLECTION) {
+ if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
+ tselem->type == TSE_LAYER_COLLECTION) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
@@ -775,6 +776,11 @@ static void object_proxy_to_override_convert_fn(bContext *C,
typedef struct OutlinerLibOverrideData {
bool do_hierarchy;
+ /**
+ * For resync operation, force keeping newly created override IDs (or original linked IDs)
+ * instead of re-applying relevant existing ID pointer property override operations. Helps
+ * solving broken overrides while not losing *all* of your overrides. */
+ bool do_resync_hierarchy_enforce;
} OutlinerLibOverrideData;
static void id_override_library_create_fn(bContext *C,
@@ -871,10 +877,12 @@ static void id_override_library_resync_fn(bContext *C,
TreeElement *te,
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
- void *UNUSED(user_data))
+ void *user_data)
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
+ OutlinerLibOverrideData *data = user_data;
+ const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
Main *bmain = CTX_data_main(C);
@@ -892,7 +900,8 @@ static void id_override_library_resync_fn(bContext *C,
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_resync(bmain, scene, CTX_data_view_layer(C), id_root);
+ BKE_lib_override_library_resync(
+ bmain, scene, CTX_data_view_layer(C), id_root, do_hierarchy_enforce);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -1044,7 +1053,7 @@ void outliner_do_object_operation_ex(bContext *C,
TreeStoreElem *tselem = TREESTORE(te);
bool select_handled = false;
if (tselem->flag & TSE_SELECTED) {
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
/* When objects selected in other scenes... dunno if that should be allowed. */
Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE);
if (scene_owner && scene_act != scene_owner) {
@@ -1601,7 +1610,7 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
- if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -1709,6 +1718,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
+ OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
@@ -1769,6 +1779,13 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Resync Library Override Hierarchy",
"Rebuild this local override from its linked reference, as well as its hierarchy of "
"dependencies"},
+ {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE,
+ "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
+ 0,
+ "Resync Library Override Hierarchy Enforce",
+ "Rebuild this local override from its linked reference, as well as its hierarchy of "
+ "dependencies, enforcing that hierarchy to match the linked data (i.e. ignoring exiting "
+ "overrides on data-blocks pointer properties)"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY,
"OVERRIDE_LIBRARY_DELETE_HIERARCHY",
0,
@@ -1803,11 +1820,6 @@ static bool outliner_id_operation_item_poll(bContext *C,
return false;
}
- Object *ob = NULL;
- if (GS(tselem->id->name) == ID_OB) {
- ob = (Object *)tselem->id;
- }
-
switch (enum_value) {
case OUTLINER_IDOP_MARK_ASSET:
case OUTLINER_IDOP_CLEAR_ASSET:
@@ -1822,21 +1834,27 @@ static bool outliner_id_operation_item_poll(bContext *C,
return true;
}
return false;
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT:
- if (ob != NULL && ob->proxy != NULL) {
- return true;
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT: {
+ if (GS(tselem->id->name) == ID_OB) {
+ Object *ob = (Object *)tselem->id;
+
+ if ((ob != NULL) && (ob->proxy != NULL)) {
+ return true;
+ }
}
return false;
+ }
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET:
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY:
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY:
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE:
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY:
if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
return true;
}
return false;
case OUTLINER_IDOP_SINGLE:
- if (!space_outliner || ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
+ if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
return true;
}
/* TODO(dalai): enable in the few cases where this can be supported
@@ -1855,7 +1873,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
EnumPropertyItem *items = NULL;
int totitem = 0;
- if (C == NULL) {
+ if ((C == NULL) || (ED_operator_outliner_active(C) == false)) {
return prop_id_op_types;
}
for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) {
@@ -2040,6 +2058,18 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: {
+ outliner_do_libdata_operation(
+ C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_override_library_resync_fn,
+ &(OutlinerLibOverrideData){.do_hierarchy = true, .do_resync_hierarchy_enforce = true});
+ ED_undo_push(C, "Resync Overridden Data Hierarchy");
+ break;
+ }
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: {
outliner_do_libdata_operation(C,
op->reports,
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index f94f19246fa..573fb492613 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -62,23 +62,14 @@
#include "BLT_translation.h"
#include "BKE_armature.h"
-#include "BKE_fcurve_driver.h"
-#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
-#include "BKE_lib_override.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_outliner_treehash.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
#include "ED_screen.h"
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "RNA_access.h"
#include "UI_interface.h"
@@ -92,9 +83,6 @@
#endif
/* prototypes */
-static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- Collection *collection,
- TreeElement *ten);
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
/* ********************************************************* */
@@ -274,7 +262,7 @@ static void outliner_add_bone(SpaceOutliner *space_outliner,
}
}
-static bool outliner_animdata_test(AnimData *adt)
+bool outliner_animdata_test(const AnimData *adt)
{
if (adt) {
return (adt->action || adt->drivers.first || adt->nla_tracks.first);
@@ -307,53 +295,13 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner,
continue;
}
linestyle->id.tag &= ~LIB_TAG_DOIT;
- outliner_add_element(space_outliner, lb, linestyle, te, 0, 0);
+ outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0);
}
}
}
}
#endif
-static void outliner_add_scene_contents(SpaceOutliner *space_outliner,
- ListBase *lb,
- Scene *sce,
- TreeElement *te)
-{
- /* View layers */
- TreeElement *ten = outliner_add_element(space_outliner, lb, sce, te, TSE_R_LAYER_BASE, 0);
- ten->name = IFACE_("View Layers");
-
- ViewLayer *view_layer;
- for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
- TreeElement *tenlay = outliner_add_element(
- space_outliner, &ten->subtree, sce, ten, TSE_R_LAYER, 0);
- tenlay->name = view_layer->name;
- tenlay->directdata = view_layer;
- }
-
- /* World */
- outliner_add_element(space_outliner, lb, sce->world, te, 0, 0);
-
- /* Collections */
- ten = outliner_add_element(space_outliner, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0);
- ten->name = IFACE_("Scene Collection");
- outliner_add_collection_recursive(space_outliner, sce->master_collection, ten);
-
- /* Objects */
- ten = outliner_add_element(space_outliner, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
- ten->name = IFACE_("Objects");
- FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
- outliner_add_element(space_outliner, &ten->subtree, ob, ten, 0, 0);
- }
- FOREACH_SCENE_OBJECT_END;
- outliner_make_object_parent_hierarchy(&ten->subtree);
-
- /* Animation Data */
- if (outliner_animdata_test(sce->adt)) {
- outliner_add_element(space_outliner, lb, sce, te, TSE_ANIM_DATA, 0);
- }
-}
-
/* Can be inlined if necessary. */
static void outliner_add_object_contents(SpaceOutliner *space_outliner,
TreeElement *te,
@@ -368,14 +316,14 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
&te->subtree,
ob->poselib,
te,
- 0,
+ TSE_SOME_ID,
0); /* XXX FIXME.. add a special type for this. */
if (ob->proxy && !ID_IS_LINKED(ob)) {
outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
}
- outliner_add_element(space_outliner, &te->subtree, ob->data, te, 0, 0);
+ outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
bArmature *arm = ob->data;
@@ -458,7 +406,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
for (int a = 0; a < ob->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a);
}
if (!BLI_listbase_is_empty(&ob->constraints)) {
@@ -624,33 +572,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
/* duplicated group */
if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) {
- outliner_add_element(space_outliner, &te->subtree, ob->instance_collection, te, 0, 0);
- }
-}
-
-static void outliner_add_library_override_contents(SpaceOutliner *soops, TreeElement *te, ID *id)
-{
- if (!id->override_library) {
- return;
- }
-
- PointerRNA idpoin;
- RNA_id_pointer_create(id, &idpoin);
-
- PointerRNA override_ptr;
- PropertyRNA *override_prop;
- int index = 0;
- LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
- if (!BKE_lib_override_rna_property_find(&idpoin, op, &override_ptr, &override_prop)) {
- /* This is fine, override properties list is not always fully up-to-date with current
- * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules,
- * no error here. */
- continue;
- }
-
- TreeElement *ten = outliner_add_element(
- soops, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE, index++);
- ten->name = RNA_property_ui_name(override_prop);
+ outliner_add_element(
+ space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0);
}
}
@@ -667,14 +590,10 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
/* expand specific data always */
switch (GS(id->name)) {
- case ID_LI: {
- te->name = ((Library *)id)->filepath;
- break;
- }
- case ID_SCE: {
- outliner_add_scene_contents(space_outliner, &te->subtree, (Scene *)id, te);
+ case ID_LI:
+ case ID_SCE:
+ BLI_assert(!"ID type expected to be expanded through new tree-element design");
break;
- }
case ID_OB: {
outliner_add_object_contents(space_outliner, te, tselem, (Object *)id);
break;
@@ -686,9 +605,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0);
}
- outliner_add_element(space_outliner, &te->subtree, me->key, te, 0, 0);
+ outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0);
for (int a = 0; a < me->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a);
}
/* could do tfaces with image links, but the images are not grouped nicely.
* would require going over all tfaces, sort images in use. etc... */
@@ -702,7 +621,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
for (int a = 0; a < cu->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a);
}
break;
}
@@ -714,7 +633,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
for (int a = 0; a < mb->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a);
}
break;
}
@@ -730,7 +649,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
if (outliner_animdata_test(tex->adt)) {
outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
}
- outliner_add_element(space_outliner, &te->subtree, tex->ima, te, 0, 0);
+ outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0);
break;
}
case ID_CA: {
@@ -901,17 +820,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
default:
break;
}
-
- const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(space_outliner) ||
- ((space_outliner->filter & SO_FILTER_NO_LIB_OVERRIDE) == 0);
-
- if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(id)) {
- TreeElement *ten = outliner_add_element(
- space_outliner, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE_BASE, 0);
-
- ten->name = IFACE_("Library Overrides");
- outliner_add_library_override_contents(space_outliner, ten, id);
- }
}
/**
@@ -972,6 +880,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
/* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some
* support this, eventually this should replace `TreeElement` entirely. */
te->type = outliner_tree_element_type_create(type, te, idv);
+ if (te->type) {
+ /* Element types ported to the new design are expected to have their name set at this point! */
+ BLI_assert(te->name != NULL);
+ }
if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
/* pass */
@@ -991,41 +903,43 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
else if (type == TSE_ID_BASE) {
/* pass */
}
+ else if (type == TSE_SOME_ID) {
+ if (!te->type) {
+ BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design");
+ }
+ }
else {
/* Other cases must be caught above. */
BLI_assert(TSE_IS_REAL_ID(tselem));
- /* do here too, for blend file viewer, own ID_LI then shows file name */
- if (GS(id->name) == ID_LI) {
- te->name = ((Library *)id)->filepath;
- }
- else {
+ /* The new type design sets the name already, don't override that here. We need to figure out
+ * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */
+ if (!te->type) {
te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */
}
te->idcode = GS(id->name);
}
- if (te->type) {
+ if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) {
outliner_tree_element_type_expand(te->type, space_outliner);
}
- else if (type == 0) {
- TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
-
- /* ID data-block. */
- if (tsepar == NULL || tsepar->type != TSE_ID_BASE || space_outliner->filter_id_type) {
+ else if (type == TSE_SOME_ID) {
+ /* ID types not (fully) ported to new design yet. */
+ if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
+ outliner_tree_element_type_post_expand(te->type, space_outliner);
}
}
- else if (ELEM(type, TSE_ANIM_DATA, TSE_DRIVER_BASE, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK)) {
+ else if (ELEM(type,
+ TSE_ANIM_DATA,
+ TSE_DRIVER_BASE,
+ TSE_NLA,
+ TSE_NLA_ACTION,
+ TSE_NLA_TRACK,
+ TSE_GP_LAYER)) {
/* Should already use new AbstractTreeElement design. */
BLI_assert(0);
}
- else if (type == TSE_GP_LAYER) {
- bGPDlayer *gpl = (bGPDlayer *)idv;
-
- te->name = gpl->info;
- te->directdata = gpl;
- }
else if (type == TSE_SEQUENCE) {
Sequence *seq = (Sequence *)idv;
@@ -1229,18 +1143,19 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner,
TreeElement *parent)
{
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- outliner_add_element(space_outliner, tree, cob->ob, parent, 0, 0);
+ outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0);
}
}
-static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- Collection *collection,
- TreeElement *ten)
+TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ Collection *collection,
+ TreeElement *ten)
{
outliner_add_collection_init(ten, collection);
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- outliner_add_element(space_outliner, &ten->subtree, &child->collection->id, ten, 0, 0);
+ outliner_add_element(
+ space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0);
}
if (space_outliner->outlinevis != SO_SCENES) {
@@ -1265,7 +1180,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb)
TreeElement *ten = te->next;
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
if (ob->parent && ob->parent->id.newid) {
BLI_remlink(lb, te);
@@ -1406,7 +1321,7 @@ static void outliner_sort(ListBase *lb)
/* sorting rules; only object lists, ID lists, or deformgroups */
if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
- (tselem->type == 0 && te->idcode == ID_OB)) {
+ ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
@@ -1420,7 +1335,7 @@ static void outliner_sort(ListBase *lb)
tp->name = te->name;
tp->idcode = te->idcode;
- if (tselem->type && tselem->type != TSE_DEFGROUP) {
+ if ((tselem->type != TSE_SOME_ID) && tselem->type != TSE_DEFGROUP) {
tp->idcode = 0; /* Don't sort this. */
}
if (tselem->type == TSE_ID_BASE) {
@@ -1471,7 +1386,7 @@ static void outliner_collections_children_sort(ListBase *lb)
TreeStoreElem *tselem = TREESTORE(te);
/* Sorting rules: only object lists. */
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
@@ -1546,7 +1461,7 @@ static bool test_collection_callback(TreeElement *te)
static bool test_object_callback(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- return ((tselem->type == 0) && (te->idcode == ID_OB));
+ return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB));
}
/**
@@ -1707,7 +1622,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
TreeStoreElem *tselem = TREESTORE(te);
- if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) {
return false;
}
@@ -1790,14 +1705,15 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return is_visible;
}
- if ((te->parent != NULL) && (TREESTORE(te->parent)->type == 0) &&
+ if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_CHILDREN) {
return false;
}
}
}
- else if (te->parent != NULL && TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) {
+ else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ (te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
return false;
}
@@ -1821,7 +1737,7 @@ static bool outliner_element_is_collection_or_object(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
return true;
}
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index 92178cfdfc9..562457c62e9 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -226,7 +226,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
if (tselem->id == id) {
return te;
}
@@ -266,7 +266,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
}
TreeStoreElem *tselem = TREESTORE(te);
- if (ELEM(tselem->type, 0, TSE_EBONE)) {
+ if (ELEM(tselem->type, TSE_SOME_ID, TSE_EBONE)) {
TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
if (tes) {
return tes;
@@ -283,7 +283,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
while (te) {
tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == idcode) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == idcode)) {
return te;
}
te = te->parent;
@@ -510,7 +510,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
if (te) {
TreeStoreElem *tselem = TREESTORE(te);
- if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob);
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
index 4ef71ded133..c0a751f2cd5 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ b/source/blender/editors/space_outliner/tree/tree_display.h
@@ -56,6 +56,10 @@ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short type,
short index);
void outliner_make_object_parent_hierarchy(ListBase *lb);
+bool outliner_animdata_test(const struct AnimData *adt);
+TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ struct Collection *collection,
+ TreeElement *ten);
const char *outliner_idcode_to_plural(short idcode);
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index cb5f42f08e1..91b690d35fa 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -111,7 +111,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
{
const short filter_id_type = id_filter_get();
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int tot;
if (filter_id_type) {
lbarray[0] = which_libbase(&mainvar, space_outliner_.filter_id_type);
@@ -144,7 +144,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
if (!tenlib) {
/* Create library tree element on demand, depending if there are any data-blocks. */
if (lib) {
- tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, 0, 0);
+ tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0);
}
else {
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
@@ -168,7 +168,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
for (ID *id : List<ID>(lbarray[a])) {
if (library_id_filter_poll(lib, id)) {
- outliner_add_element(&space_outliner_, &ten->subtree, id, ten, 0, 0);
+ outliner_add_element(&space_outliner_, &ten->subtree, id, ten, TSE_SOME_ID, 0);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
index 0b17ea98831..69ccf014642 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -42,7 +42,7 @@ TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner)
ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
short filter_id_type = (space_outliner_.filter & SO_FILTER_ID_TYPE) ?
space_outliner_.filter_id_type :
0;
@@ -76,7 +76,8 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data)
/* Add the orphaned data-blocks - these will not be added with any subtrees attached. */
for (ID *id : List<ID>(lbarray[a])) {
if (ID_REAL_USERS(id) <= 0) {
- outliner_add_element(&space_outliner_, (te) ? &te->subtree : &tree, id, te, 0, 0);
+ outliner_add_element(
+ &space_outliner_, (te) ? &te->subtree : &tree, id, te, TSE_SOME_ID, 0);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index f377512d81e..390f81cfcd1 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -46,7 +46,8 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data)
for (ID *id : List<ID>(source_data.bmain->scenes)) {
Scene *scene = reinterpret_cast<Scene *>(id);
- TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0);
+ TreeElement *te = outliner_add_element(
+ &space_outliner_, &tree, scene, nullptr, TSE_SOME_ID, 0);
TreeStoreElem *tselem = TREESTORE(te);
/* New scene elements open by default */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index a0ebac5f451..89c9960a24f 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -80,7 +80,7 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data)
/* Show objects in the view layer. */
for (Base *base : List<Base>(view_layer_->object_bases)) {
TreeElement *te_object = outliner_add_element(
- &space_outliner_, &tree, base->object, nullptr, 0, 0);
+ &space_outliner_, &tree, base->object, nullptr, TSE_SOME_ID, 0);
te_object->directdata = base;
}
@@ -158,7 +158,7 @@ void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree,
for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) {
Base *base = BKE_view_layer_base_find(view_layer_, cob->ob);
TreeElement *te_object = outliner_add_element(
- &space_outliner_, &tree, base->object, &ten, 0, 0);
+ &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0);
te_object->directdata = base;
}
}
@@ -203,7 +203,7 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl
continue;
}
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
/* Lookup children or add new, empty children vector. */
Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
@@ -261,8 +261,12 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
if (!found) {
/* We add the child in the tree even if it is not in the collection.
* We deliberately clear its sub-tree though, to make it less prominent. */
- TreeElement *child_ob_tree_element = outliner_add_element(
- &outliner_, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0);
+ TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
+ &parent_ob_tree_element->subtree,
+ child,
+ parent_ob_tree_element,
+ TSE_SOME_ID,
+ 0);
outliner_free_tree(&child_ob_tree_element->subtree);
child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
child_ob_tree_elements.append(child_ob_tree_element);
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 27846614994..113d421ed91 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -18,11 +18,18 @@
* \ingroup spoutliner
*/
+#include "DNA_anim_types.h"
#include "DNA_listBase.h"
#include "tree_element_anim_data.hh"
-#include "tree_element_driver_base.hh"
+#include "tree_element_collection.hh"
+#include "tree_element_driver.hh"
+#include "tree_element_gpencil_layer.hh"
+#include "tree_element_id.hh"
#include "tree_element_nla.hh"
+#include "tree_element_overrides.hh"
+#include "tree_element_scene_objects.hh"
+#include "tree_element_view_layer.hh"
#include "tree_element.h"
#include "tree_element.hh"
@@ -31,13 +38,25 @@ namespace blender::ed::outliner {
static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv)
{
- /* Would be nice to get rid of void * here, can we somehow expect the right type right away?
- * Perfect forwarding maybe, once the API is C++ only? */
ID &id = *static_cast<ID *>(idv);
+ /*
+ * The following calls make an implicit assumption about what data was passed to the `idv`
+ * argument of #outliner_add_element(). The old code does this already, here we just centralize
+ * it as much as possible for now. Would be nice to entirely get rid of that, no more `void *`.
+ *
+ * Once #outliner_add_element() is sufficiently simplified, it should be replaced by a C++ call.
+ * It could take the derived type as template parameter (e.g. #TreeElementAnimData) and use C++
+ * perfect forwarding to pass any data to the type's constructor.
+ * If general Outliner code wants to access the data, they can query that through the derived
+ * element type then. There's no need for `void *` anymore then.
+ */
+
switch (type) {
+ case TSE_SOME_ID:
+ return TreeElementID::createFromID(legacy_te, id);
case TSE_ANIM_DATA:
- return new TreeElementAnimData(legacy_te, id);
+ return new TreeElementAnimData(legacy_te, *reinterpret_cast<IdAdtTemplate &>(id).adt);
case TSE_DRIVER_BASE:
return new TreeElementDriverBase(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA:
@@ -45,7 +64,20 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
case TSE_NLA_TRACK:
return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv));
case TSE_NLA_ACTION:
- return new TreeElementNLAAction(legacy_te);
+ return new TreeElementNLAAction(legacy_te, *static_cast<bAction *>(idv));
+ case TSE_GP_LAYER:
+ return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv));
+ case TSE_R_LAYER_BASE:
+ return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv));
+ case TSE_SCENE_COLLECTION_BASE:
+ return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv));
+ case TSE_SCENE_OBJECTS_BASE:
+ return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv));
+ case TSE_LIBRARY_OVERRIDE_BASE:
+ return new TreeElementOverridesBase(legacy_te, id);
+ case TSE_LIBRARY_OVERRIDE:
+ return new TreeElementOverridesProperty(legacy_te,
+ *static_cast<TreeElementOverridesData *>(idv));
default:
break;
}
@@ -61,7 +93,33 @@ static void tree_element_free(AbstractTreeElement **tree_element)
static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
{
+ /* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common
+ * expanding. Could be done nicer, we could request a small "expander" helper object from the
+ * element type, that the IDs have a more advanced implementation for. */
+ if (!tree_element.expandPoll(space_outliner)) {
+ return;
+ }
tree_element.expand(space_outliner);
+ tree_element.postExpand(space_outliner);
+}
+
+/**
+ * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be
+ * removed once all ID types expand entirely using the new design.
+ */
+static void tree_element_post_expand_only(AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner)
+{
+ tree_element.postExpand(space_outliner);
+}
+/**
+ * Needed for types that still expand in C, to poll if they should expand in current context. Can
+ * be removed once all ID types expand entirely using the new design.
+ */
+static bool tree_element_expand_poll(AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner)
+{
+ return tree_element.expandPoll(space_outliner);
}
} // namespace blender::ed::outliner
@@ -79,6 +137,22 @@ void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *spa
outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
*space_outliner);
}
+bool outliner_tree_element_type_is_expand_valid(TreeElementType *type)
+{
+ outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>(
+ *type);
+ return element.isExpandValid();
+}
+bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner)
+{
+ return outliner::tree_element_expand_poll(
+ reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner);
+}
+void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner)
+{
+ outliner::tree_element_post_expand_only(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
+ *space_outliner);
+}
void outliner_tree_element_type_free(TreeElementType **type)
{
diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h
index d88c37180b3..8e5b02278cc 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.h
+++ b/source/blender/editors/space_outliner/tree/tree_element.h
@@ -39,6 +39,9 @@ TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy
void outliner_tree_element_type_free(TreeElementType **type);
void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner);
+bool outliner_tree_element_type_is_expand_valid(TreeElementType *type);
+bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner);
+void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 8a1ebb51eae..09bd0eec05d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -37,17 +37,39 @@ class AbstractTreeElement {
TreeElement &legacy_te_;
public:
- AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
- {
- }
virtual ~AbstractTreeElement() = default;
/**
+ * Check if the type is expandable in current context.
+ */
+ virtual bool expandPoll(const SpaceOutliner &) const
+ {
+ return true;
+ }
+ /**
* Let the type add its own children.
*/
virtual void expand(SpaceOutliner &) const
{
}
+ virtual void postExpand(SpaceOutliner &) const
+ {
+ }
+
+ /**
+ * Just while transitioning to the new tree-element design: Some types are only partially ported,
+ * and the expanding isn't done yet.
+ */
+ virtual bool isExpandValid() const
+ {
+ return true;
+ }
+
+ protected:
+ /* Pseudo-abstract: Only allow creation through derived types. */
+ AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
+ {
+ }
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
index 13a25800800..c0fef7c98e2 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
@@ -32,8 +32,8 @@
namespace blender::ed::outliner {
-TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id)
- : AbstractTreeElement(legacy_te), anim_data_(*reinterpret_cast<IdAdtTemplate &>(id).adt)
+TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, AnimData &anim_data)
+ : AbstractTreeElement(legacy_te), anim_data_(anim_data)
{
BLI_assert(legacy_te.store_elem->type == TSE_ANIM_DATA);
/* this element's info */
@@ -44,7 +44,8 @@ TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id)
void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const
{
/* Animation data-block itself. */
- outliner_add_element(&space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, 0, 0);
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0);
expand_drivers(space_outliner);
expand_NLA_tracks(space_outliner);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh
index 8114277b6d6..95d08cd20b7 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh
@@ -30,7 +30,7 @@ class TreeElementAnimData final : public AbstractTreeElement {
AnimData &anim_data_;
public:
- TreeElementAnimData(TreeElement &legacy_te, ID &id);
+ TreeElementAnimData(TreeElement &legacy_te, AnimData &anim_data);
void expand(SpaceOutliner &space_outliner) const override;
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
new file mode 100644
index 00000000000..1add61db7f1
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_collection.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementCollectionBase::TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene)
+ : AbstractTreeElement(legacy_te), scene_(scene)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SCENE_COLLECTION_BASE);
+ legacy_te.name = IFACE_("Scene Collection");
+}
+
+void TreeElementCollectionBase::expand(SpaceOutliner &space_outliner) const
+{
+ outliner_add_collection_recursive(&space_outliner, scene_.master_collection, &legacy_te_);
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.hh b/source/blender/editors/space_outliner/tree/tree_element_collection.hh
new file mode 100644
index 00000000000..e9584d37dfe
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.hh
@@ -0,0 +1,36 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementCollectionBase final : public AbstractTreeElement {
+ Scene &scene_;
+
+ public:
+ TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
index a01a3c42531..42f51908eaa 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
@@ -30,7 +30,7 @@
#include "../outliner_intern.h"
#include "tree_display.h"
-#include "tree_element_driver_base.hh"
+#include "tree_element_driver.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh b/source/blender/editors/space_outliner/tree/tree_element_driver.hh
index 1925e3570be..1925e3570be 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.hh
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
new file mode 100644
index 00000000000..91e6fdcde4b
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "../outliner_intern.h"
+
+#include "tree_element_gpencil_layer.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementGPencilLayer::TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer)
+ : AbstractTreeElement(legacy_te)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_GP_LAYER);
+ /* this element's info */
+ legacy_te.name = gplayer.info;
+ legacy_te.directdata = &gplayer;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh
new file mode 100644
index 00000000000..da57ef63f1f
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh
@@ -0,0 +1,34 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+struct bGPDlayer;
+
+namespace blender::ed::outliner {
+
+class TreeElementGPencilLayer final : public AbstractTreeElement {
+ public:
+ TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer);
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
new file mode 100644
index 00000000000..ce99b954204
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -0,0 +1,135 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "DNA_ID.h"
+
+#include "BLI_listbase_wrapper.hh"
+#include "BLI_utildefines.h"
+
+#include "BKE_lib_override.h"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+#include "tree_element_id_library.hh"
+#include "tree_element_id_scene.hh"
+
+#include "tree_element_id.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
+{
+ switch (ID_Type type = GS(id.name); type) {
+ case ID_LI:
+ return new TreeElementIDLibrary(legacy_te, (Library &)id);
+ case ID_SCE:
+ return new TreeElementIDScene(legacy_te, (Scene &)id);
+ case ID_OB:
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ case ID_MA:
+ case ID_TE:
+ case ID_LT:
+ case ID_LA:
+ case ID_CA:
+ case ID_KE:
+ case ID_SCR:
+ case ID_WO:
+ case ID_SPK:
+ case ID_GR:
+ case ID_NT:
+ case ID_BR:
+ case ID_PA:
+ case ID_MC:
+ case ID_MSK:
+ case ID_LS:
+ case ID_LP:
+ case ID_GD:
+ case ID_WS:
+ case ID_HA:
+ case ID_PT:
+ case ID_VO:
+ case ID_SIM:
+ case ID_WM:
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_AC:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ return new TreeElementID(legacy_te, id);
+ /* Deprecated */
+ case ID_IP:
+ BLI_assert(!"Outliner trying to build tree-element for deprecated ID type");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+/* -------------------------------------------------------------------- */
+/* ID Tree-Element Base Class (common/default logic) */
+
+TreeElementID::TreeElementID(TreeElement &legacy_te, ID &id)
+ : AbstractTreeElement(legacy_te), id_(id)
+{
+ BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID);
+ BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem));
+
+ /* Default, some specific types override this. */
+ legacy_te_.name = id.name + 2;
+ legacy_te_.idcode = GS(id.name);
+}
+
+void TreeElementID::postExpand(SpaceOutliner &space_outliner) const
+{
+ const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner) ||
+ ((space_outliner.filter & SO_FILTER_NO_LIB_OVERRIDE) == 0);
+
+ if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY_REAL(&id_)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE_BASE, 0);
+ }
+}
+
+bool TreeElementID::expandPoll(const SpaceOutliner &space_outliner) const
+{
+ const TreeStoreElem *tsepar = legacy_te_.parent ? TREESTORE(legacy_te_.parent) : nullptr;
+ return (tsepar == nullptr || tsepar->type != TSE_ID_BASE || space_outliner.filter_id_type);
+}
+
+void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner,
+ const AnimData *anim_data) const
+{
+ if (outliner_animdata_test(anim_data)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_ANIM_DATA, 0);
+ }
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh
new file mode 100644
index 00000000000..b3b5ca2770c
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.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.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ *
+ * Tree element classes for the tree elements directly representing an ID (#TSE_SOME_ID).
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementID : public AbstractTreeElement {
+ protected:
+ ID &id_;
+
+ public:
+ TreeElementID(TreeElement &legacy_te, ID &id);
+
+ static TreeElementID *createFromID(TreeElement &legacy_te, ID &id);
+
+ void postExpand(SpaceOutliner &) const override;
+ bool expandPoll(const SpaceOutliner &) const override;
+
+ /**
+ * Expanding not implemented for all types yet. Once it is, this can be set to true or
+ * `AbstractTreeElement::expandValid()` can be removed altogether.
+ */
+ bool isExpandValid() const override
+ {
+ return false;
+ }
+
+ protected:
+ /* ID types with animation data can use this. */
+ void expand_animation_data(SpaceOutliner &, const AnimData *) const;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
new file mode 100644
index 00000000000..36f536c9845
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "../outliner_intern.h"
+
+#include "tree_element_id_library.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, Library &library)
+ : TreeElementID(legacy_te, library.id)
+{
+ legacy_te.name = library.filepath;
+}
+
+bool TreeElementIDLibrary::isExpandValid() const
+{
+ return true;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
new file mode 100644
index 00000000000..88660cd8aa9
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
@@ -0,0 +1,34 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element_id.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementIDLibrary final : public TreeElementID {
+ public:
+ TreeElementIDLibrary(TreeElement &legacy_te, Library &library);
+
+ bool isExpandValid() const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
new file mode 100644
index 00000000000..ae81b44a1e4
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.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 spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_id_scene.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementIDScene::TreeElementIDScene(TreeElement &legacy_te, Scene &scene)
+ : TreeElementID(legacy_te, scene.id), scene_(scene)
+{
+}
+
+bool TreeElementIDScene::isExpandValid() const
+{
+ return true;
+}
+
+void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const
+{
+ expandViewLayers(space_outliner);
+ expandWorld(space_outliner);
+ expandCollections(space_outliner);
+ expandObjects(space_outliner);
+
+ expand_animation_data(space_outliner, scene_.adt);
+}
+
+void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0);
+}
+
+void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0);
+}
+
+void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0);
+}
+
+void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0);
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh
new file mode 100644
index 00000000000..3340bacd307
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh
@@ -0,0 +1,43 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element_id.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementIDScene final : public TreeElementID {
+ Scene &scene_;
+
+ public:
+ TreeElementIDScene(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+ bool isExpandValid() const override;
+
+ private:
+ void expandViewLayers(SpaceOutliner &) const;
+ void expandWorld(SpaceOutliner &) const;
+ void expandCollections(SpaceOutliner &) const;
+ void expandObjects(SpaceOutliner &) const;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
index 5d4ec53e60c..65832e8f981 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
@@ -70,9 +70,11 @@ void TreeElementNLATrack::expand(SpaceOutliner &space_outliner) const
/* -------------------------------------------------------------------- */
-TreeElementNLAAction::TreeElementNLAAction(TreeElement &legacy_te) : AbstractTreeElement(legacy_te)
+TreeElementNLAAction::TreeElementNLAAction(TreeElement &legacy_te, const bAction &action)
+ : AbstractTreeElement(legacy_te)
{
BLI_assert(legacy_te.store_elem->type == TSE_NLA_ACTION);
+ legacy_te.name = action.id.name + 2;
}
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh
index c94287ce576..7cbc8689483 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_nla.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh
@@ -46,7 +46,7 @@ class TreeElementNLATrack final : public AbstractTreeElement {
class TreeElementNLAAction final : public AbstractTreeElement {
public:
- TreeElementNLAAction(TreeElement &legacy_te);
+ TreeElementNLAAction(TreeElement &legacy_te, const bAction &action);
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
new file mode 100644
index 00000000000..6b222e877b1
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -0,0 +1,84 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "BKE_collection.h"
+#include "BKE_lib_override.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_listbase_wrapper.hh"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_overrides.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementOverridesBase::TreeElementOverridesBase(TreeElement &legacy_te, ID &id)
+ : AbstractTreeElement(legacy_te), id_(id)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE_BASE);
+ legacy_te.name = IFACE_("Library Overrides");
+}
+
+void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
+{
+ BLI_assert(id_.override_library != nullptr);
+
+ PointerRNA idpoin;
+ RNA_id_pointer_create(&id_, &idpoin);
+
+ PointerRNA override_rna_ptr;
+ PropertyRNA *override_rna_prop;
+ short index = 0;
+
+ for (auto *override_prop :
+ ListBaseWrapper<IDOverrideLibraryProperty>(id_.override_library->properties)) {
+ if (!BKE_lib_override_rna_property_find(
+ &idpoin, override_prop, &override_rna_ptr, &override_rna_prop)) {
+ /* This is fine, override properties list is not always fully up-to-date with current
+ * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules,
+ * no error here. */
+ continue;
+ }
+
+ TreeElementOverridesData data = {id_, *override_prop};
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &data, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++);
+ }
+}
+
+TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_te,
+ TreeElementOverridesData &override_data)
+ : AbstractTreeElement(legacy_te),
+ id_(override_data.id),
+ override_prop_(override_data.override_property)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE);
+
+ legacy_te.name = override_prop_.rna_path;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
new file mode 100644
index 00000000000..b5c772f5b33
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -0,0 +1,49 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+struct TreeElementOverridesData {
+ ID &id;
+ IDOverrideLibraryProperty &override_property;
+};
+
+class TreeElementOverridesBase final : public AbstractTreeElement {
+ ID &id_;
+
+ public:
+ TreeElementOverridesBase(TreeElement &legacy_te, ID &id);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+class TreeElementOverridesProperty final : public AbstractTreeElement {
+ ID &id_;
+ IDOverrideLibraryProperty &override_prop_;
+
+ public:
+ TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
new file mode 100644
index 00000000000..a46e8de1bdd
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "BKE_collection.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_scene_objects.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene)
+ : AbstractTreeElement(legacy_te), scene_(scene)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SCENE_OBJECTS_BASE);
+ legacy_te.name = IFACE_("Objects");
+}
+
+void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const
+{
+ FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) {
+ outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0);
+ }
+ FOREACH_SCENE_OBJECT_END;
+ outliner_make_object_parent_hierarchy(&legacy_te_.subtree);
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
new file mode 100644
index 00000000000..a2aa29c4a33
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
@@ -0,0 +1,36 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementSceneObjectsBase final : public AbstractTreeElement {
+ Scene &scene_;
+
+ public:
+ TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
new file mode 100644
index 00000000000..7bb9405147e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
@@ -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.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_layer_types.h"
+
+#include "BLI_listbase_wrapper.hh"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_view_layer.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementViewLayerBase::TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene)
+ : AbstractTreeElement(legacy_te), scene_(scene)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_R_LAYER_BASE);
+ legacy_te_.name = IFACE_("View Layers");
+}
+
+void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const
+{
+ for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene_.view_layers)) {
+ TreeElement *tenlay = outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0);
+ tenlay->name = view_layer->name;
+ tenlay->directdata = view_layer;
+ }
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh
new file mode 100644
index 00000000000..24e03b265dc
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh
@@ -0,0 +1,36 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementViewLayerBase final : public AbstractTreeElement {
+ Scene &scene_;
+
+ public:
+ TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 037ce78b9a2..5d6d24dae74 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -37,8 +38,10 @@
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -55,6 +58,7 @@
#include "SEQ_add.h"
#include "SEQ_effects.h"
+#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_select.h"
@@ -548,6 +552,55 @@ static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr),
return !(STR_ELEM(prop_id, "filepath", "directory", "filename"));
}
+/* Strips are added in context of timeline which has different preview size than actual preview. We
+ * must search for preview area. In most cases there will be only one preview area, but there can
+ * be more with different preview sizes. */
+static IMB_Proxy_Size seq_get_proxy_size_flags(bContext *C)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ IMB_Proxy_Size proxy_sizes = 0;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ if (!ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
+ continue;
+ }
+ proxy_sizes |= SEQ_rendersize_to_proxysize(sseq->render_size);
+ }
+ }
+ }
+ }
+ return proxy_sizes;
+}
+
+static void seq_build_proxy(bContext *C, Sequence *seq)
+{
+ if (U.sequencer_proxy_setup != USER_SEQ_PROXY_SETUP_AUTOMATIC) {
+ return;
+ }
+
+ /* Enable and set proxy size. */
+ SEQ_proxy_set(seq, true);
+ seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+
+ /* Build proxy. */
+ GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+ wmJob *wm_job = ED_seq_proxy_wm_job_get(C);
+ ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job);
+ SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ BLI_gset_free(file_list, MEM_freeN);
+
+ if (!WM_jobs_is_running(wm_job)) {
+ G.is_break = false;
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
static void sequencer_add_movie_multiple_strips(bContext *C,
wmOperator *op,
SeqLoadData *load_data)
@@ -578,6 +631,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
+ seq_build_proxy(C, seq_movie);
}
}
RNA_END;
@@ -604,6 +658,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
}
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
+ seq_build_proxy(C, seq_movie);
return true;
}
@@ -924,9 +979,7 @@ static int sequencer_add_image_strip_calculate_length(wmOperator *op,
if (use_placeholders) {
return sequencer_image_seq_get_minmax_frame(op, start_frame, minframe, numdigits);
}
- else {
- return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
- }
+ return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
}
static void sequencer_add_image_strip_load_files(
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9828368ccf7..3249eae8c7f 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1312,6 +1312,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
SEQ_render_new_render_data(
bmain, depsgraph, scene, rectx, recty, sseq->render_size, false, &context);
context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
+ context.use_proxies = (sseq->flag & SEQ_USE_PROXIES) != 0;
/* Sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Escape pressed somewhere in the past. */
@@ -2112,7 +2113,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
typedef struct CacheDrawData {
struct View2D *v2d;
- float stripe_offs;
+ float stripe_ofs_y;
float stripe_ht;
int cache_flag;
GPUVertBuf *raw_vbo;
@@ -2151,7 +2152,7 @@ static bool draw_cache_view_iter_fn(void *userdata,
{
CacheDrawData *drawdata = userdata;
struct View2D *v2d = drawdata->v2d;
- float stripe_bot, stripe_top, stripe_offs, stripe_ht;
+ float stripe_bot, stripe_top, stripe_ofs_y, stripe_ht;
GPUVertBuf *vbo;
size_t *vert_count;
@@ -2164,27 +2165,27 @@ static bool draw_cache_view_iter_fn(void *userdata,
vert_count = &drawdata->final_out_vert_count;
}
else if ((cache_type & SEQ_CACHE_STORE_RAW) && (drawdata->cache_flag & SEQ_CACHE_VIEW_RAW)) {
- stripe_offs = drawdata->stripe_offs;
+ stripe_ofs_y = drawdata->stripe_ofs_y;
stripe_ht = drawdata->stripe_ht;
- stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
vbo = drawdata->raw_vbo;
vert_count = &drawdata->raw_vert_count;
}
else if ((cache_type & SEQ_CACHE_STORE_PREPROCESSED) &&
(drawdata->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED)) {
- stripe_offs = drawdata->stripe_offs;
+ stripe_ofs_y = drawdata->stripe_ofs_y;
stripe_ht = drawdata->stripe_ht;
- stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_offs + stripe_ht) + stripe_offs;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_ofs_y + stripe_ht) + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
vbo = drawdata->preprocessed_vbo;
vert_count = &drawdata->preprocessed_vert_count;
}
else if ((cache_type & SEQ_CACHE_STORE_COMPOSITE) &&
(drawdata->cache_flag & SEQ_CACHE_VIEW_COMPOSITE)) {
- stripe_offs = drawdata->stripe_offs;
+ stripe_ofs_y = drawdata->stripe_ofs_y;
stripe_ht = drawdata->stripe_ht;
- stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs;
+ stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
stripe_bot = stripe_top - stripe_ht;
vbo = drawdata->composite_vbo;
vert_count = &drawdata->composite_vert_count;
@@ -2237,12 +2238,12 @@ static void draw_cache_view(const bContext *C)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
float stripe_bot, stripe_top;
- float stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
+ float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) -
v2d->cur.ymin;
CLAMP_MAX(stripe_ht, 0.2f);
- CLAMP_MIN(stripe_offs, stripe_ht / 2);
+ CLAMP_MIN(stripe_ofs_y, stripe_ht / 2);
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) {
stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HANDLE_HEIGHT);
@@ -2262,7 +2263,7 @@ static void draw_cache_view(const bContext *C)
continue;
}
- stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
@@ -2271,7 +2272,7 @@ static void draw_cache_view(const bContext *C)
immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
}
- stripe_bot += stripe_ht + stripe_offs;
+ stripe_bot += stripe_ht + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
@@ -2280,7 +2281,7 @@ static void draw_cache_view(const bContext *C)
immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
}
- stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs;
+ stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
stripe_bot = stripe_top - stripe_ht;
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
@@ -2297,7 +2298,7 @@ static void draw_cache_view(const bContext *C)
CacheDrawData userdata;
userdata.v2d = v2d;
- userdata.stripe_offs = stripe_offs;
+ userdata.stripe_ofs_y = stripe_ofs_y;
userdata.stripe_ht = stripe_ht;
userdata.cache_flag = scene->ed->cache_flag;
userdata.raw_vert_count = 0;
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 4c942a83f2b..767ac76efe6 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -79,7 +79,7 @@ struct Sequence *find_neighboring_sequence(struct Scene *scene,
struct Sequence *test,
int lr,
int sel);
-void recurs_sel_seq(struct Sequence *seqm);
+void recurs_sel_seq(struct Sequence *seq_meta);
int seq_effect_find_selected(struct Scene *scene,
struct Sequence *activeseq,
int type,
diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c
index 24fa4ad7a17..e44afde371a 100644
--- a/source/blender/editors/space_sequencer/sequencer_proxy.c
+++ b/source/blender/editors/space_sequencer/sequencer_proxy.c
@@ -49,98 +49,25 @@
/* Own include. */
#include "sequencer_intern.h"
-/*--------------------------------------------------------------------*/
-/** \name Proxy Job Manager
+/* -------------------------------------------------------------------- */
+/** \name Rebuild Proxy and Timecode Indices Operator
* \{ */
-typedef struct ProxyBuildJob {
- struct Main *main;
- struct Depsgraph *depsgraph;
- Scene *scene;
- ListBase queue;
- int stop;
-} ProxyJob;
-
-static void proxy_freejob(void *pjv)
-{
- ProxyJob *pj = pjv;
-
- BLI_freelistN(&pj->queue);
-
- MEM_freeN(pj);
-}
-
-/* Only this runs inside thread. */
-static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
-{
- ProxyJob *pj = pjv;
- LinkData *link;
-
- for (link = pj->queue.first; link; link = link->next) {
- struct SeqIndexBuildContext *context = link->data;
-
- SEQ_proxy_rebuild(context, stop, do_update, progress);
-
- if (*stop) {
- pj->stop = 1;
- fprintf(stderr, "Canceling proxy rebuild on users request...\n");
- break;
- }
- }
-}
-
-static void proxy_endjob(void *pjv)
-{
- ProxyJob *pj = pjv;
- Editing *ed = SEQ_editing_get(pj->scene, false);
- LinkData *link;
-
- for (link = pj->queue.first; link; link = link->next) {
- SEQ_proxy_rebuild_finish(link->data, pj->stop);
- }
-
- SEQ_relations_free_imbuf(pj->scene, &ed->seqbase, false);
-
- WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
-}
-
static void seq_proxy_build_job(const bContext *C, ReportList *reports)
{
- wmJob *wm_job;
- ProxyJob *pj;
- struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, false);
ScrArea *area = CTX_wm_area(C);
Sequence *seq;
- GSet *file_list;
if (ed == NULL) {
return;
}
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- scene,
- "Building Proxies",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_SEQ_BUILD_PROXY);
-
- pj = WM_jobs_customdata_get(wm_job);
-
- if (!pj) {
- pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
-
- pj->depsgraph = depsgraph;
- pj->scene = scene;
- pj->main = CTX_data_main(C);
+ wmJob *wm_job = ED_seq_proxy_wm_job_get(C);
+ ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job);
- WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
- WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
- }
-
- file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+ GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
bool selected = false; /* Check for no selected strips */
SEQ_CURRENT_BEGIN (ed, seq) {
@@ -182,12 +109,6 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
ED_area_tag_redraw(area);
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Rebuild Proxy and Timecode Indices Operator
- * \{ */
-
static int sequencer_rebuild_proxy_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
new file mode 100644
index 00000000000..a77e74ffd93
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -0,0 +1,50 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blenfont
+ ../../bmesh
+ ../../depsgraph
+ ../../functions
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/glew-mx
+ ../../../../intern/guardedalloc
+)
+
+set(SRC
+ space_spreadsheet.cc
+ spreadsheet_column_layout.cc
+ spreadsheet_draw.cc
+ spreadsheet_from_geometry.cc
+ spreadsheet_ops.cc
+
+ spreadsheet_draw.hh
+ spreadsheet_column_layout.hh
+ spreadsheet_from_geometry.hh
+ spreadsheet_intern.hh
+)
+
+set(LIB
+)
+
+blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
new file mode 100644
index 00000000000..05759c1b510
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -0,0 +1,364 @@
+/*
+ * 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 <cstring>
+
+#include "BLI_listbase.h"
+#include "BLI_resource_collector.hh"
+
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "spreadsheet_intern.hh"
+
+#include "spreadsheet_column_layout.hh"
+#include "spreadsheet_from_geometry.hh"
+#include "spreadsheet_intern.hh"
+
+using namespace blender::ed::spreadsheet;
+
+static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
+{
+ SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
+ "spreadsheet space");
+ spreadsheet_space->spacetype = SPACE_SPREADSHEET;
+
+ {
+ /* Header. */
+ ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
+ BLI_addtail(&spreadsheet_space->regionbase, region);
+ region->regiontype = RGN_TYPE_HEADER;
+ region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ }
+
+ {
+ /* Footer. */
+ ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region");
+ BLI_addtail(&spreadsheet_space->regionbase, region);
+ region->regiontype = RGN_TYPE_FOOTER;
+ region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
+ }
+
+ {
+ /* Main window. */
+ ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
+ BLI_addtail(&spreadsheet_space->regionbase, region);
+ region->regiontype = RGN_TYPE_WINDOW;
+ }
+
+ return (SpaceLink *)spreadsheet_space;
+}
+
+static void spreadsheet_free(SpaceLink *sl)
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ MEM_SAFE_FREE(sspreadsheet->runtime);
+}
+
+static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
+ if (sspreadsheet->runtime == nullptr) {
+ sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN(
+ sizeof(SpaceSpreadsheet_Runtime), __func__);
+ }
+}
+
+static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
+{
+ const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
+ SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
+ sspreadsheet_new->runtime = (SpaceSpreadsheet_Runtime *)MEM_dupallocN(sspreadsheet_old->runtime);
+
+ return (SpaceLink *)sspreadsheet_new;
+}
+
+static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
+{
+}
+
+static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
+{
+ region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM;
+ region->v2d.align = V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y;
+ region->v2d.keepzoom = V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT;
+ region->v2d.keeptot = V2D_KEEPTOT_STRICT;
+ region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
+
+ UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
+
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
+ WM_event_add_keymap_handler(&region->handlers, keymap);
+}
+
+static ID *get_used_id(const bContext *C)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ if (sspreadsheet->pinned_id != nullptr) {
+ return sspreadsheet->pinned_id;
+ }
+ Object *active_object = CTX_data_active_object(C);
+ return (ID *)active_object;
+}
+
+class FallbackSpreadsheetDrawer : public SpreadsheetDrawer {
+};
+
+static void gather_spreadsheet_columns(const bContext *C,
+ SpreadsheetColumnLayout &column_layout,
+ blender::ResourceCollector &resources)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ID *used_id = get_used_id(C);
+ if (used_id == nullptr) {
+ return;
+ }
+ const ID_Type id_type = GS(used_id->name);
+ if (id_type != ID_OB) {
+ return;
+ }
+ Object *object_orig = (Object *)used_id;
+ if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD)) {
+ return;
+ }
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig);
+ if (object_eval == nullptr) {
+ return;
+ }
+
+ return spreadsheet_columns_from_geometry(C, object_eval, column_layout, resources);
+}
+
+static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+
+ blender::ResourceCollector resources;
+ SpreadsheetColumnLayout column_layout;
+ gather_spreadsheet_columns(C, column_layout, resources);
+
+ sspreadsheet->runtime->visible_rows = column_layout.row_indices.size();
+ sspreadsheet->runtime->tot_columns = column_layout.columns.size();
+ sspreadsheet->runtime->tot_rows = column_layout.tot_rows;
+
+ std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_column_layout(column_layout);
+ draw_spreadsheet_in_region(C, region, *drawer);
+
+ /* Tag footer for redraw, because the main region updates data for the footer. */
+ ARegion *footer = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_FOOTER);
+ ED_region_tag_redraw(footer);
+}
+
+static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
+{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
+ switch (wmn->category) {
+ case NC_SCENE: {
+ switch (wmn->data) {
+ case ND_MODE:
+ case ND_FRAME:
+ case ND_OB_ACTIVE: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+ break;
+ }
+ case NC_OBJECT: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ case NC_SPACE: {
+ if (wmn->data == ND_SPACE_SPREADSHEET) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
+ case NC_GEOM: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+}
+
+static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
+{
+ ED_region_header_init(region);
+}
+
+static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
+{
+ ED_region_header(C, region);
+}
+
+static void spreadsheet_header_region_free(ARegion *UNUSED(region))
+{
+}
+
+static void spreadsheet_header_region_listener(const wmRegionListenerParams *params)
+{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
+ switch (wmn->category) {
+ case NC_SCENE: {
+ switch (wmn->data) {
+ case ND_MODE:
+ case ND_OB_ACTIVE: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+ break;
+ }
+ case NC_OBJECT: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ case NC_SPACE: {
+ if (wmn->data == ND_SPACE_SPREADSHEET) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
+ case NC_GEOM: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+}
+
+static void spreadsheet_footer_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
+{
+ ED_region_header_init(region);
+}
+
+static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ SpaceSpreadsheet_Runtime *runtime = sspreadsheet->runtime;
+ std::stringstream ss;
+ ss << "Rows: ";
+ if (runtime->visible_rows != runtime->tot_rows) {
+ ss << runtime->visible_rows << " / ";
+ }
+ ss << runtime->tot_rows << " | Columns: " << runtime->tot_columns;
+ std::string stats_str = ss.str();
+
+ UI_ThemeClearColor(TH_BACK);
+
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ const uiStyle *style = UI_style_get_dpi();
+ uiLayout *layout = UI_block_layout(block,
+ UI_LAYOUT_HORIZONTAL,
+ UI_LAYOUT_HEADER,
+ UI_HEADER_OFFSET,
+ region->winy - (region->winy - UI_UNIT_Y) / 2.0f,
+ region->sizex,
+ 1,
+ 0,
+ style);
+ uiItemSpacer(layout);
+ uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(layout, stats_str.c_str(), ICON_NONE);
+ UI_block_layout_resolve(block, nullptr, nullptr);
+ UI_block_align_end(block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
+}
+
+static void spreadsheet_footer_region_free(ARegion *UNUSED(region))
+{
+}
+
+static void spreadsheet_footer_region_listener(const wmRegionListenerParams *UNUSED(params))
+{
+}
+
+void ED_spacetype_spreadsheet(void)
+{
+ SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
+ ARegionType *art;
+
+ st->spaceid = SPACE_SPREADSHEET;
+ strncpy(st->name, "Spreadsheet", BKE_ST_MAXNAME);
+
+ st->create = spreadsheet_create;
+ st->free = spreadsheet_free;
+ st->init = spreadsheet_init;
+ st->duplicate = spreadsheet_duplicate;
+ st->operatortypes = spreadsheet_operatortypes;
+ st->keymap = spreadsheet_keymap;
+
+ /* regions: main window */
+ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
+ art->regionid = RGN_TYPE_WINDOW;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
+
+ art->init = spreadsheet_main_region_init;
+ art->draw = spreadsheet_main_region_draw;
+ art->listener = spreadsheet_main_region_listener;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: header */
+ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
+ art->regionid = RGN_TYPE_HEADER;
+ art->prefsizey = HEADERY;
+ art->keymapflag = 0;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+
+ art->init = spreadsheet_header_region_init;
+ art->draw = spreadsheet_header_region_draw;
+ art->free = spreadsheet_header_region_free;
+ art->listener = spreadsheet_header_region_listener;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: footer */
+ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region");
+ art->regionid = RGN_TYPE_FOOTER;
+ art->prefsizey = HEADERY;
+ art->keymapflag = 0;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+
+ art->init = spreadsheet_footer_region_init;
+ art->draw = spreadsheet_footer_region_draw;
+ art->free = spreadsheet_footer_region_free;
+ art->listener = spreadsheet_footer_region_listener;
+ BLI_addhead(&st->regiontypes, art);
+
+ BKE_spacetype_register(st);
+}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc
new file mode 100644
index 00000000000..4faf0cac2c0
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc
@@ -0,0 +1,189 @@
+/*
+ * 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 <iomanip>
+#include <sstream>
+
+#include "spreadsheet_column_layout.hh"
+
+#include "DNA_userdef_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BLF_api.h"
+
+namespace blender::ed::spreadsheet {
+
+class ColumnLayoutDrawer : public SpreadsheetDrawer {
+ private:
+ const SpreadsheetColumnLayout &column_layout_;
+ Vector<int> column_widths_;
+
+ public:
+ ColumnLayoutDrawer(const SpreadsheetColumnLayout &column_layout) : column_layout_(column_layout)
+ {
+ tot_columns = column_layout.columns.size();
+ tot_rows = column_layout.row_indices.size();
+
+ const int fontid = UI_style_get()->widget.uifont_id;
+ /* Use a consistent font size for the width calculation. */
+ BLF_size(fontid, 11 * U.pixelsize, U.dpi);
+
+ /* The width of the index column depends on the maximum row index. */
+ left_column_width = std::to_string(std::max(0, column_layout_.tot_rows - 1)).size() *
+ BLF_width(fontid, "0", 1) +
+ UI_UNIT_X * 0.75;
+
+ /* The column widths depend on the column name widths. */
+ const int minimum_column_width = 3 * UI_UNIT_X;
+ const int header_name_padding = UI_UNIT_X;
+ for (const SpreadsheetColumn *column : column_layout_.columns) {
+ StringRefNull name = column->name();
+ const int name_width = BLF_width(fontid, name.data(), name.size());
+ const int width = std::max(name_width + header_name_padding, minimum_column_width);
+ column_widths_.append(width);
+ }
+ }
+
+ void draw_top_row_cell(int column_index, const CellDrawParams &params) const final
+ {
+ const StringRefNull name = column_layout_.columns[column_index]->name();
+ uiBut *but = uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_NONE,
+ name.c_str(),
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ /* Center-align column headers. */
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_RIGHT);
+ }
+
+ void draw_left_column_cell(int row_index, const CellDrawParams &params) const final
+ {
+ const int real_index = column_layout_.row_indices[row_index];
+ std::string index_str = std::to_string(real_index);
+ uiBut *but = uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_NONE,
+ index_str.c_str(),
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ /* Right-align indices. */
+ UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+ }
+
+ void draw_content_cell(int row_index, int column_index, const CellDrawParams &params) const final
+ {
+ const int real_index = column_layout_.row_indices[row_index];
+ const SpreadsheetColumn &column = *column_layout_.columns[column_index];
+ CellValue cell_value;
+ column.get_value(real_index, cell_value);
+
+ if (std::holds_alternative<int>(cell_value.value)) {
+ const int value = *std::get_if<int>(&cell_value.value);
+ const std::string value_str = std::to_string(value);
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_NONE,
+ value_str.c_str(),
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
+ else if (std::holds_alternative<float>(cell_value.value)) {
+ const float value = *std::get_if<float>(&cell_value.value);
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(3) << value;
+ const std::string value_str = ss.str();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_NONE,
+ value_str.c_str(),
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
+ else if (std::holds_alternative<bool>(cell_value.value)) {
+ const bool value = *std::get_if<bool>(&cell_value.value);
+ const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ icon,
+ "",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
+ }
+
+ int column_width(int column_index) const final
+ {
+ return column_widths_[column_index];
+ }
+};
+
+std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_column_layout(
+ const SpreadsheetColumnLayout &column_layout)
+{
+ return std::make_unique<ColumnLayoutDrawer>(column_layout);
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh
new file mode 100644
index 00000000000..a3832f42f30
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <variant>
+
+#include "spreadsheet_draw.hh"
+
+namespace blender::ed::spreadsheet {
+
+/**
+ * This is a small type that can hold the value of a cell in a spreadsheet. This type allows us to
+ * decouple the drawing of individual cells from the code that generates the data to be displayed.
+ */
+class CellValue {
+ public:
+ /* The implementation just uses a `std::variant` for simplicity. It can be encapsulated better,
+ * but it's not really worth the complixity for now. */
+ using VariantType = std::variant<std::monostate, int, float, bool>;
+
+ VariantType value;
+};
+
+/**
+ * This represents a column in a spreadsheet. It has a name and provides a value for all the cells
+ * in the column.
+ */
+class SpreadsheetColumn {
+ protected:
+ std::string name_;
+
+ public:
+ SpreadsheetColumn(std::string name) : name_(std::move(name))
+ {
+ }
+
+ virtual ~SpreadsheetColumn() = default;
+
+ virtual void get_value(int index, CellValue &r_cell_value) const = 0;
+
+ StringRefNull name() const
+ {
+ return name_;
+ }
+};
+
+/* Utility class for the function below. */
+template<typename GetValueF> class LambdaSpreadsheetColumn : public SpreadsheetColumn {
+ private:
+ GetValueF get_value_;
+
+ public:
+ LambdaSpreadsheetColumn(std::string name, GetValueF get_value)
+ : SpreadsheetColumn(std::move(name)), get_value_(std::move(get_value))
+ {
+ }
+
+ void get_value(int index, CellValue &r_cell_value) const final
+ {
+ get_value_(index, r_cell_value);
+ }
+};
+
+/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
+template<typename GetValueF>
+std::unique_ptr<SpreadsheetColumn> spreadsheet_column_from_function(std::string name,
+ GetValueF get_value)
+{
+ return std::make_unique<LambdaSpreadsheetColumn<GetValueF>>(std::move(name),
+ std::move(get_value));
+}
+
+/* This contains information required to create a spreadsheet drawer from columns. */
+struct SpreadsheetColumnLayout {
+ Vector<const SpreadsheetColumn *> columns;
+ Span<int64_t> row_indices;
+ int tot_rows = 0;
+};
+
+std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_column_layout(
+ const SpreadsheetColumnLayout &column_layout);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
new file mode 100644
index 00000000000..d6379c740e8
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
@@ -0,0 +1,304 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "GPU_immediate.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_rect.h"
+
+#include "spreadsheet_draw.hh"
+
+namespace blender::ed::spreadsheet {
+
+SpreadsheetDrawer::SpreadsheetDrawer()
+{
+ left_column_width = UI_UNIT_X * 2;
+ top_row_height = UI_UNIT_Y * 1.1f;
+ row_height = UI_UNIT_Y;
+}
+
+SpreadsheetDrawer::~SpreadsheetDrawer() = default;
+
+void SpreadsheetDrawer::draw_top_row_cell(int UNUSED(column_index),
+ const CellDrawParams &UNUSED(params)) const
+{
+}
+
+void SpreadsheetDrawer::draw_left_column_cell(int UNUSED(row_index),
+ const CellDrawParams &UNUSED(params)) const
+{
+}
+
+void SpreadsheetDrawer::draw_content_cell(int UNUSED(row_index),
+ int UNUSED(column_index),
+ const CellDrawParams &UNUSED(params)) const
+{
+}
+
+int SpreadsheetDrawer::column_width(int UNUSED(column_index)) const
+{
+ return 5 * UI_UNIT_X;
+}
+
+static void draw_index_column_background(const uint pos,
+ const ARegion *region,
+ const SpreadsheetDrawer &drawer)
+{
+ immUniformThemeColorShade(TH_BACK, 11);
+ immRecti(pos, 0, region->winy - drawer.top_row_height, drawer.left_column_width, 0);
+}
+
+static void draw_alternating_row_overlay(const uint pos,
+ const int scroll_offset_y,
+ const ARegion *region,
+ const SpreadsheetDrawer &drawer)
+{
+ immUniformThemeColor(TH_ROW_ALTERNATE);
+ GPU_blend(GPU_BLEND_ALPHA);
+ BLI_assert(drawer.row_height > 0);
+ const int row_pair_height = drawer.row_height * 2;
+ const int row_top_y = region->winy - drawer.top_row_height - scroll_offset_y % row_pair_height;
+ for (const int i : IndexRange(region->winy / row_pair_height + 1)) {
+ int x_left = 0;
+ int x_right = region->winx;
+ int y_top = row_top_y - i * row_pair_height - drawer.row_height;
+ int y_bottom = y_top - drawer.row_height;
+ y_top = std::min(y_top, region->winy - drawer.top_row_height);
+ y_bottom = std::min(y_bottom, region->winy - drawer.top_row_height);
+ immRecti(pos, x_left, y_top, x_right, y_bottom);
+ }
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+static void draw_top_row_background(const uint pos,
+ const ARegion *region,
+ const SpreadsheetDrawer &drawer)
+{
+ immUniformThemeColorShade(TH_BACK, 11);
+ immRecti(pos, 0, region->winy, region->winx, region->winy - drawer.top_row_height);
+}
+
+static void draw_separator_lines(const uint pos,
+ const int scroll_offset_x,
+ const ARegion *region,
+ const SpreadsheetDrawer &drawer)
+{
+ immUniformThemeColorShade(TH_BACK, -11);
+
+ immBeginAtMost(GPU_PRIM_LINES, drawer.tot_columns * 2 + 4);
+
+ /* Left column line. */
+ immVertex2i(pos, drawer.left_column_width, region->winy);
+ immVertex2i(pos, drawer.left_column_width, 0);
+
+ /* Top row line. */
+ immVertex2i(pos, 0, region->winy - drawer.top_row_height);
+ immVertex2i(pos, region->winx, region->winy - drawer.top_row_height);
+
+ /* Column separator lines. */
+ int line_x = drawer.left_column_width - scroll_offset_x;
+ for (const int column_index : IndexRange(drawer.tot_columns)) {
+ const int column_width = drawer.column_width(column_index);
+ line_x += column_width;
+ if (line_x >= drawer.left_column_width) {
+ immVertex2i(pos, line_x, region->winy);
+ immVertex2i(pos, line_x, 0);
+ }
+ }
+ immEnd();
+}
+
+static void get_visible_rows(const SpreadsheetDrawer &drawer,
+ const ARegion *region,
+ const int scroll_offset_y,
+ int *r_first_row,
+ int *r_max_visible_rows)
+{
+ *r_first_row = -scroll_offset_y / drawer.row_height;
+ *r_max_visible_rows = region->winy / drawer.row_height + 1;
+}
+
+static void draw_left_column_content(const int scroll_offset_y,
+ const bContext *C,
+ ARegion *region,
+ const SpreadsheetDrawer &drawer)
+{
+ GPU_scissor_test(true);
+ GPU_scissor(0, 0, drawer.left_column_width, region->winy - drawer.top_row_height);
+
+ uiBlock *left_column_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
+ int first_row, max_visible_rows;
+ get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows);
+ for (const int row_index : IndexRange(first_row, max_visible_rows)) {
+ if (row_index >= drawer.tot_rows) {
+ break;
+ }
+ CellDrawParams params;
+ params.block = left_column_block;
+ params.xmin = 0;
+ params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
+ scroll_offset_y;
+ params.width = drawer.left_column_width;
+ params.height = drawer.row_height;
+ drawer.draw_left_column_cell(row_index, params);
+ }
+
+ UI_block_end(C, left_column_block);
+ UI_block_draw(C, left_column_block);
+
+ GPU_scissor_test(false);
+}
+
+static void draw_top_row_content(const bContext *C,
+ ARegion *region,
+ const SpreadsheetDrawer &drawer,
+ const int scroll_offset_x)
+{
+ GPU_scissor_test(true);
+ GPU_scissor(drawer.left_column_width + 1,
+ region->winy - drawer.top_row_height,
+ region->winx - drawer.left_column_width,
+ drawer.top_row_height);
+
+ uiBlock *first_row_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
+
+ int left_x = drawer.left_column_width - scroll_offset_x;
+ for (const int column_index : IndexRange(drawer.tot_columns)) {
+ const int column_width = drawer.column_width(column_index);
+ const int right_x = left_x + column_width;
+
+ CellDrawParams params;
+ params.block = first_row_block;
+ params.xmin = left_x;
+ params.ymin = region->winy - drawer.top_row_height;
+ params.width = column_width;
+ params.height = drawer.top_row_height;
+ drawer.draw_top_row_cell(column_index, params);
+
+ left_x = right_x;
+ }
+
+ UI_block_end(C, first_row_block);
+ UI_block_draw(C, first_row_block);
+
+ GPU_scissor_test(false);
+}
+
+static void draw_cell_contents(const bContext *C,
+ ARegion *region,
+ const SpreadsheetDrawer &drawer,
+ const int scroll_offset_x,
+ const int scroll_offset_y)
+{
+ GPU_scissor_test(true);
+ GPU_scissor(drawer.left_column_width + 1,
+ 0,
+ region->winx - drawer.left_column_width,
+ region->winy - drawer.top_row_height);
+
+ uiBlock *cells_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
+
+ int first_row, max_visible_rows;
+ get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows);
+
+ int left_x = drawer.left_column_width - scroll_offset_x;
+ for (const int column_index : IndexRange(drawer.tot_columns)) {
+ const int column_width = drawer.column_width(column_index);
+ const int right_x = left_x + column_width;
+
+ if (right_x >= drawer.left_column_width && left_x <= region->winx) {
+ for (const int row_index : IndexRange(first_row, max_visible_rows)) {
+ if (row_index >= drawer.tot_rows) {
+ break;
+ }
+
+ CellDrawParams params;
+ params.block = cells_block;
+ params.xmin = left_x;
+ params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
+ scroll_offset_y;
+ params.width = column_width;
+ params.height = drawer.row_height;
+ drawer.draw_content_cell(row_index, column_index, params);
+ }
+ }
+
+ left_x = right_x;
+ }
+
+ UI_block_end(C, cells_block);
+ UI_block_draw(C, cells_block);
+
+ GPU_scissor_test(false);
+}
+
+static void update_view2d_tot_rect(const SpreadsheetDrawer &drawer,
+ ARegion *region,
+ const int row_amount)
+{
+ int column_width_sum = 0;
+ for (const int column_index : IndexRange(drawer.tot_columns)) {
+ column_width_sum += drawer.column_width(column_index);
+ }
+
+ UI_view2d_totRect_set(&region->v2d,
+ column_width_sum + drawer.left_column_width,
+ row_amount * drawer.row_height + drawer.top_row_height);
+}
+
+void draw_spreadsheet_in_region(const bContext *C,
+ ARegion *region,
+ const SpreadsheetDrawer &drawer)
+{
+ update_view2d_tot_rect(drawer, region, drawer.tot_rows);
+
+ UI_ThemeClearColor(TH_BACK);
+
+ View2D *v2d = &region->v2d;
+ const int scroll_offset_y = v2d->cur.ymax;
+ const int scroll_offset_x = v2d->cur.xmin;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ draw_index_column_background(pos, region, drawer);
+ draw_alternating_row_overlay(pos, scroll_offset_y, region, drawer);
+ draw_top_row_background(pos, region, drawer);
+ draw_separator_lines(pos, scroll_offset_x, region, drawer);
+
+ immUnbindProgram();
+
+ draw_left_column_content(scroll_offset_y, C, region, drawer);
+ draw_top_row_content(C, region, drawer, scroll_offset_x);
+ draw_cell_contents(C, region, drawer, scroll_offset_x, scroll_offset_y);
+
+ rcti scroller_mask;
+ BLI_rcti_init(&scroller_mask,
+ drawer.left_column_width,
+ region->winx,
+ 0,
+ region->winy - drawer.top_row_height);
+ UI_view2d_scrollers_draw(v2d, &scroller_mask);
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_draw.hh
new file mode 100644
index 00000000000..6828006f4a1
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.hh
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BLI_vector.hh"
+
+struct uiBlock;
+struct rcti;
+struct bContext;
+struct ARegion;
+
+namespace blender::ed::spreadsheet {
+
+struct CellDrawParams {
+ uiBlock *block;
+ int xmin, ymin;
+ int width, height;
+};
+
+class SpreadsheetDrawer {
+ public:
+ int left_column_width;
+ int top_row_height;
+ int row_height;
+ int tot_rows = 0;
+ int tot_columns = 0;
+
+ SpreadsheetDrawer();
+ virtual ~SpreadsheetDrawer();
+
+ virtual void draw_top_row_cell(int column_index, const CellDrawParams &params) const;
+
+ virtual void draw_left_column_cell(int row_index, const CellDrawParams &params) const;
+
+ virtual void draw_content_cell(int row_index,
+ int column_index,
+ const CellDrawParams &params) const;
+
+ virtual int column_width(int column_index) const;
+};
+
+void draw_spreadsheet_in_region(const bContext *C,
+ ARegion *region,
+ const SpreadsheetDrawer &spreadsheet_drawer);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc
new file mode 100644
index 00000000000..0ba405d97e0
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc
@@ -0,0 +1,380 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "bmesh.h"
+
+#include "spreadsheet_from_geometry.hh"
+#include "spreadsheet_intern.hh"
+
+namespace blender::ed::spreadsheet {
+
+using blender::bke::ReadAttribute;
+using blender::bke::ReadAttributePtr;
+
+static Vector<std::string> get_sorted_attribute_names_to_display(
+ const GeometryComponent &component, const AttributeDomain domain)
+{
+ Vector<std::string> attribute_names;
+ component.attribute_foreach(
+ [&](const StringRef attribute_name, const AttributeMetaData &meta_data) {
+ if (meta_data.domain == domain) {
+ attribute_names.append(attribute_name);
+ }
+ return true;
+ });
+ std::sort(attribute_names.begin(),
+ attribute_names.end(),
+ [](const std::string &a, const std::string &b) {
+ return BLI_strcasecmp_natural(a.c_str(), b.c_str()) < 0;
+ });
+ return attribute_names;
+}
+
+static void add_columns_for_attribute(const ReadAttribute *attribute,
+ const StringRefNull attribute_name,
+ Vector<std::unique_ptr<SpreadsheetColumn>> &columns)
+{
+ const CustomDataType data_type = attribute->custom_data_type();
+ switch (data_type) {
+ case CD_PROP_FLOAT: {
+ columns.append(spreadsheet_column_from_function(
+ attribute_name, [attribute](int index, CellValue &r_cell_value) {
+ float value;
+ attribute->get(index, &value);
+ r_cell_value.value = value;
+ }));
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ static std::array<char, 2> axis_char = {'X', 'Y'};
+ for (const int i : {0, 1}) {
+ std::string name = attribute_name + " " + axis_char[i];
+ columns.append(spreadsheet_column_from_function(
+ name, [attribute, i](int index, CellValue &r_cell_value) {
+ float2 value;
+ attribute->get(index, &value);
+ r_cell_value.value = value[i];
+ }));
+ }
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ static std::array<char, 3> axis_char = {'X', 'Y', 'Z'};
+ for (const int i : {0, 1, 2}) {
+ std::string name = attribute_name + " " + axis_char[i];
+ columns.append(spreadsheet_column_from_function(
+ name, [attribute, i](int index, CellValue &r_cell_value) {
+ float3 value;
+ attribute->get(index, &value);
+ r_cell_value.value = value[i];
+ }));
+ }
+ break;
+ }
+ case CD_PROP_COLOR: {
+ static std::array<char, 4> axis_char = {'R', 'G', 'B', 'A'};
+ for (const int i : {0, 1, 2, 3}) {
+ std::string name = attribute_name + " " + axis_char[i];
+ columns.append(spreadsheet_column_from_function(
+ name, [attribute, i](int index, CellValue &r_cell_value) {
+ Color4f value;
+ attribute->get(index, &value);
+ r_cell_value.value = value[i];
+ }));
+ }
+ break;
+ }
+ case CD_PROP_INT32: {
+ columns.append(spreadsheet_column_from_function(
+ attribute_name, [attribute](int index, CellValue &r_cell_value) {
+ int value;
+ attribute->get(index, &value);
+ r_cell_value.value = value;
+ }));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ columns.append(spreadsheet_column_from_function(
+ attribute_name, [attribute](int index, CellValue &r_cell_value) {
+ bool value;
+ attribute->get(index, &value);
+ r_cell_value.value = value;
+ }));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
+ Object *object_eval,
+ const GeometryComponentType used_component_type)
+{
+ GeometrySet geometry_set;
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
+ if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
+ Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
+ if (mesh == nullptr) {
+ return geometry_set;
+ }
+ BKE_mesh_wrapper_ensure_mdata(mesh);
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ mesh_component.copy_vertex_group_names_from_object(*object_eval);
+ }
+ else {
+ if (object_eval->runtime.geometry_set_eval != nullptr) {
+ /* This does not copy the geometry data itself. */
+ geometry_set = *object_eval->runtime.geometry_set_eval;
+ }
+ }
+ }
+ else {
+ Object *object_orig = DEG_get_original_object(object_eval);
+ if (object_orig->type == OB_MESH) {
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ if (object_orig->mode == OB_MODE_EDIT) {
+ Mesh *mesh = (Mesh *)object_orig->data;
+ BMEditMesh *em = mesh->edit_mesh;
+ if (em != nullptr) {
+ Mesh *new_mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ /* This is a potentially heavy operation to do on every redraw. The best solution here is
+ * to display the data directly from the bmesh without a conversion, which can be
+ * implemented a bit later. */
+ BM_mesh_bm_to_me_for_eval(em->bm, new_mesh, nullptr);
+ mesh_component.replace(new_mesh, GeometryOwnershipType::Owned);
+ }
+ }
+ else {
+ Mesh *mesh = (Mesh *)object_orig->data;
+ mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ }
+ mesh_component.copy_vertex_group_names_from_object(*object_orig);
+ }
+ else if (object_orig->type == OB_POINTCLOUD) {
+ PointCloud *pointcloud = (PointCloud *)object_orig->data;
+ PointCloudComponent &pointcloud_component =
+ geometry_set.get_component_for_write<PointCloudComponent>();
+ pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
+ }
+ }
+ return geometry_set;
+}
+
+using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
+
+static void get_selected_vertex_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_vertex_indices)
+{
+ for (const int i : IndexRange(mesh.totvert)) {
+ if (is_vertex_selected_fn(i)) {
+ r_vertex_indices.append(i);
+ }
+ }
+}
+
+static void get_selected_corner_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_corner_indices)
+{
+ for (const int i : IndexRange(mesh.totloop)) {
+ const MLoop &loop = mesh.mloop[i];
+ if (is_vertex_selected_fn(loop.v)) {
+ r_corner_indices.append(i);
+ }
+ }
+}
+
+static void get_selected_polygon_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_polygon_indices)
+{
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ bool is_selected = true;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (!is_vertex_selected_fn(loop.v)) {
+ is_selected = false;
+ break;
+ }
+ }
+ if (is_selected) {
+ r_polygon_indices.append(poly_index);
+ }
+ }
+}
+
+static void get_selected_edge_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_edge_indices)
+{
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[i];
+ if (is_vertex_selected_fn(edge.v1) && is_vertex_selected_fn(edge.v2)) {
+ r_edge_indices.append(i);
+ }
+ }
+}
+
+static void get_selected_indices_on_domain(const Mesh &mesh,
+ const AttributeDomain domain,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_indices)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices);
+ case ATTR_DOMAIN_POLYGON:
+ return get_selected_polygon_indices(mesh, is_vertex_selected_fn, r_indices);
+ case ATTR_DOMAIN_CORNER:
+ return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices);
+ case ATTR_DOMAIN_EDGE:
+ return get_selected_edge_indices(mesh, is_vertex_selected_fn, r_indices);
+ default:
+ return;
+ }
+}
+
+static Span<int64_t> filter_mesh_elements_by_selection(const bContext *C,
+ Object *object_eval,
+ const MeshComponent *component,
+ const AttributeDomain domain,
+ ResourceCollector &resources)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ const bool show_only_selected = sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY;
+ if (object_eval->mode == OB_MODE_EDIT && show_only_selected) {
+ Object *object_orig = DEG_get_original_object(object_eval);
+ Vector<int64_t> &visible_rows = resources.construct<Vector<int64_t>>("visible rows");
+ const Mesh *mesh_eval = component->get_for_read();
+ Mesh *mesh_orig = (Mesh *)object_orig->data;
+ BMesh *bm = mesh_orig->edit_mesh->bm;
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
+ if (orig_indices != nullptr) {
+ /* Use CD_ORIGINDEX layer if it exists. */
+ auto is_vertex_selected = [&](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ BMVert *vert = bm->vtable[i_orig];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ };
+ get_selected_indices_on_domain(*mesh_eval, domain, is_vertex_selected, visible_rows);
+ }
+ else if (mesh_eval->totvert == bm->totvert) {
+ /* Use a simple heuristic to match original vertices to evaluated ones. */
+ auto is_vertex_selected = [&](int vertex_index) -> bool {
+ BMVert *vert = bm->vtable[vertex_index];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ };
+ get_selected_indices_on_domain(*mesh_eval, domain, is_vertex_selected, visible_rows);
+ }
+ /* This is safe, because the vector lives in the resource collector. */
+ return visible_rows.as_span();
+ }
+ /* No filter is used. */
+ const int domain_size = component->attribute_domain_size(domain);
+ return IndexRange(domain_size).as_span();
+}
+
+static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
+ return (GeometryComponentType)sspreadsheet->geometry_component_type;
+ }
+ if (object_eval->type == OB_POINTCLOUD) {
+ return GEO_COMPONENT_TYPE_POINT_CLOUD;
+ }
+ return GEO_COMPONENT_TYPE_MESH;
+}
+
+void spreadsheet_columns_from_geometry(const bContext *C,
+ Object *object_eval,
+ SpreadsheetColumnLayout &column_layout,
+ ResourceCollector &resources)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
+ const GeometryComponentType component_type = get_display_component_type(C, object_eval);
+
+ /* Create a resource collector that owns stuff that needs to live until drawing is done. */
+ GeometrySet &geometry_set = resources.add_value(
+ get_display_geometry_set(sspreadsheet, object_eval, component_type), "geometry set");
+
+ const GeometryComponent *component = geometry_set.get_component_for_read(component_type);
+ if (component == nullptr) {
+ return;
+ }
+ if (!component->attribute_domain_supported(domain)) {
+ return;
+ }
+
+ Vector<std::string> attribute_names = get_sorted_attribute_names_to_display(*component, domain);
+
+ Vector<std::unique_ptr<SpreadsheetColumn>> &columns =
+ resources.construct<Vector<std::unique_ptr<SpreadsheetColumn>>>("columns");
+
+ for (StringRefNull attribute_name : attribute_names) {
+ ReadAttributePtr attribute_ptr = component->attribute_try_get_for_read(attribute_name);
+ ReadAttribute &attribute = *attribute_ptr;
+ resources.add(std::move(attribute_ptr), "attribute");
+ add_columns_for_attribute(&attribute, attribute_name, columns);
+ }
+
+ for (std::unique_ptr<SpreadsheetColumn> &column : columns) {
+ column_layout.columns.append(column.get());
+ }
+
+ /* The filter below only works for mesh vertices currently. */
+ Span<int64_t> visible_rows;
+ if (component_type == GEO_COMPONENT_TYPE_MESH) {
+ visible_rows = filter_mesh_elements_by_selection(
+ C, object_eval, static_cast<const MeshComponent *>(component), domain, resources);
+ }
+ else {
+ visible_rows = IndexRange(component->attribute_domain_size(domain)).as_span();
+ }
+
+ const int domain_size = component->attribute_domain_size(domain);
+ column_layout.row_indices = visible_rows;
+ column_layout.tot_rows = domain_size;
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh
new file mode 100644
index 00000000000..cef731517b9
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BKE_geometry_set.hh"
+
+#include "BLI_resource_collector.hh"
+
+#include "spreadsheet_column_layout.hh"
+
+struct bContext;
+
+namespace blender::ed::spreadsheet {
+
+void spreadsheet_columns_from_geometry(const bContext *C,
+ Object *object_eval,
+ SpreadsheetColumnLayout &column_layout,
+ ResourceCollector &resources);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
new file mode 100644
index 00000000000..7e3b79a6706
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+typedef struct SpaceSpreadsheet_Runtime {
+ int visible_rows;
+ int tot_rows;
+ int tot_columns;
+} SpaceSpreadsheet_Runtime;
+
+void spreadsheet_operatortypes(void);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
new file mode 100644
index 00000000000..770bd207e8d
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
@@ -0,0 +1,21 @@
+/*
+ * 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 "spreadsheet_intern.hh"
+
+void spreadsheet_operatortypes()
+{
+}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 36da0791c4f..17f60dfc210 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1575,7 +1575,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
}
/* default for now */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index c75d9796265..48f274ca71b 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -1438,6 +1438,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve
const int cube_verts[3] = {3, 1, 4};
for (int i = 0; i < 3; i++) {
scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
+ /* Primitives have size 2 by default, compensate for this here. */
+ scale[i] /= 2.0f;
}
wmOperatorType *ot = NULL;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 0605ea30806..7dc4a72e510 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1673,8 +1673,8 @@ static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15)
static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9)
{
- const int offs = 4 * hits15;
- memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(uint));
+ const int ofs = 4 * hits15;
+ memcpy(buffer, buffer + ofs, 4 * hits9 * sizeof(uint));
return hits9;
}
@@ -1683,8 +1683,8 @@ static int selectbuffer_ret_hits_5(uint *buffer,
const int hits9,
const int hits5)
{
- const int offs = 4 * hits15 + 4 * hits9;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
+ const int ofs = 4 * hits15 + 4 * hits9;
+ memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -1726,30 +1726,30 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
goto finally;
}
else if (hits15 > 0) {
- int offs;
+ int ofs;
has_bones15 = selectbuffer_has_bones(buffer, hits15);
- offs = 4 * hits15;
+ ofs = 4 * hits15;
BLI_rcti_init_pt_radius(&rect, mval, 9);
hits9 = view3d_opengl_select(
- vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
+ vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter);
if (hits9 == 1) {
hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
goto finally;
}
else if (hits9 > 0) {
- has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
+ has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9);
- offs += 4 * hits9;
+ ofs += 4 * hits9;
BLI_rcti_init_pt_radius(&rect, mval, 5);
hits5 = view3d_opengl_select(
- vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
+ vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
goto finally;
}
else if (hits5 > 0) {
- has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
+ has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index cce9287679c..72c62321e88 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -667,7 +667,7 @@ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); /* hrm */
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* hrm */
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
return OPERATOR_FINISHED;
@@ -910,10 +910,9 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r
static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
if (snap_calc_active_center(C, false, scene->cursor.location)) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 24335b6b6b7..4b43592165b 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -429,6 +429,20 @@ typedef struct TransCustomDataContainer {
} TransCustomDataContainer;
#define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(TransCustomDataContainer) / sizeof(TransCustomData))
+/**
+ * Container for Transform Data
+ *
+ * Used to implement multi-object modes, so each object can have it's
+ * own data array as well as object matrix, local center etc.
+ *
+ * Anything that can't be shared between all objects
+ * and doesn't make sense to store for every vertex (in the #TransDataContainer.data).
+ *
+ * \note at some point this could be used to store non object containers
+ * although this only makes sense if each container has it's own matrices,
+ * otherwise all elements may as well be stored in one array (#TransDataContainer.data),
+ * as is already done for curve-objects, f-curves. etc.
+ */
typedef struct TransDataContainer {
/** Transformed data (array). */
TransData *data;
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 93d5d41e121..2037981e655 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -550,7 +550,7 @@ static void applyObjectConstraintSize(TransInfo *t,
}
static void constraints_rotation_impl(TransInfo *t,
- float axismtx[3][3],
+ const float axismtx[3][3],
float r_vec[3],
float *r_angle)
{
@@ -572,7 +572,8 @@ static void constraints_rotation_impl(TransInfo *t,
break;
}
/* don't flip axis if asked to or if num input */
- if (r_angle && !((mode & CON_NOFLIP) || hasNumInput(&t->num) || (t->flag & T_INPUT_IS_VALUES_FINAL))) {
+ if (r_angle &&
+ !((mode & CON_NOFLIP) || hasNumInput(&t->num) || (t->flag & T_INPUT_IS_VALUES_FINAL))) {
float view_vector[3];
view_vector_calc(t, t->center_global, view_vector);
if (dot_v3v3(r_vec, view_vector) > 0.0f) {
@@ -620,7 +621,7 @@ static void applyObjectConstraintRot(
{
if (t->con.mode & CON_APPLY) {
float tmp_axismtx[3][3];
- float(*axismtx)[3];
+ const float(*axismtx)[3];
/* on setup call, use first object */
if (td == NULL) {
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 244cd552495..45df0e66691 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -37,6 +37,7 @@
#include "BKE_gpencil_geom.h"
#include "ED_gpencil.h"
+#include "ED_keyframing.h"
#include "transform.h"
#include "transform_convert.h"
@@ -114,6 +115,7 @@ static void createTransGPencil_curves(bContext *C,
#define SEL_F3 (1 << 2)
View3D *v3d = t->view;
+ Scene *scene = CTX_data_scene(C);
const bool handle_only_selected_visible = (v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
const bool handle_all_visible = (v3d->overlay.handle_display == CURVE_HANDLE_ALL);
@@ -230,7 +232,9 @@ static void createTransGPencil_curves(bContext *C,
}
if ((gpf->framenum != cfra) && (!is_multiedit)) {
- gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ if (IS_AUTOKEY_ON(scene)) {
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ }
/* in some weird situations (framelock enabled) return NULL */
if (gpf == NULL) {
continue;
@@ -405,6 +409,7 @@ static void createTransGPencil_strokes(bContext *C,
const bool is_prop_edit_connected,
const bool is_scale_thickness)
{
+ Scene *scene = CTX_data_scene(C);
TransData *td = NULL;
float mtx[3][3], smtx[3][3];
@@ -517,7 +522,9 @@ static void createTransGPencil_strokes(bContext *C,
* spent too much time editing the wrong frame...
*/
if ((gpf->framenum != cfra) && (!is_multiedit)) {
- gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ if (IS_AUTOKEY_ON(scene)) {
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ }
/* in some weird situations (framelock enabled) return NULL */
if (gpf == NULL) {
continue;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 01c00247a7a..9b5f15a2574 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -163,14 +163,13 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = {
static int select_orientation_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
int orientation = RNA_enum_get(op->ptr, "orientation");
BKE_scene_orientation_slot_set_index(&scene->orientation_slots[SCE_ORIENT_DEFAULT], orientation);
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
WM_msg_publish_rna_prop(mbus, &scene->id, scene, TransformOrientationSlot, type);
@@ -286,7 +285,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 7d8f72f3779..b69f62a2875 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -224,6 +224,28 @@ static void ed_undo_step_post(bContext *C,
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ScrArea *area = CTX_wm_area(C);
+
+ /* Set special modes for grease pencil */
+ if (area != NULL && (area->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->type == OB_GPENCIL)) {
+ /* set cursor */
+ if (ELEM(obact->mode,
+ OB_MODE_PAINT_GPENCIL,
+ OB_MODE_SCULPT_GPENCIL,
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL)) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ else {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ /* set workspace mode */
+ Base *basact = CTX_data_active_base(C);
+ ED_object_base_activate(C, basact);
+ }
+ }
/* App-Handlers (post). */
{
@@ -911,9 +933,7 @@ void ED_undo_object_editmode_restore_helper(struct bContext *C,
* and local collections may be used.
* \{ */
-static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
- Object *obact,
- int *r_active_index)
+static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, Object *obact)
{
const short object_type = obact->type;
@@ -929,9 +949,6 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
- if (ob == obact) {
- *r_active_index = len;
- }
ID *id = ob->data;
if ((id->tag & LIB_TAG_DOIT) == 0) {
len += 1;
@@ -944,16 +961,18 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
{
- Object *obact = OBACT(view_layer);
- if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
+ Base *baseact = BASACT(view_layer);
+ if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
return MEM_mallocN(0, __func__);
}
- int active_index = 0;
- const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
- const short object_type = obact->type;
+ const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
+ const short object_type = baseact->object->type;
int i = 0;
Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ /* Base iteration, starting with the active-base to ensure it's the first item in the array.
+ * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
+ for (Base *base = baseact, *base_next = FIRSTBASE(view_layer); base;
+ base = base_next, base_next = base_next ? base_next->next : NULL) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
@@ -964,25 +983,25 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
}
}
BLI_assert(i == len);
- if (active_index > 0) {
- SWAP(Object *, objects[0], objects[active_index]);
- }
+ BLI_assert(objects[0] == baseact->object);
*r_len = len;
return objects;
}
Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
{
- Object *obact = OBACT(view_layer);
- if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
+ Base *baseact = BASACT(view_layer);
+ if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
return MEM_mallocN(0, __func__);
}
- int active_index = 0;
- const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
- const short object_type = obact->type;
+ const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
+ const short object_type = baseact->object->type;
int i = 0;
Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ /* Base iteration, starting with the active-base to ensure it's the first item in the array.
+ * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
+ for (Base *base = BASACT(view_layer), *base_next = FIRSTBASE(view_layer); base;
+ base = base_next, base_next = base_next ? base_next->next : NULL) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
@@ -992,10 +1011,9 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len
}
}
}
+
BLI_assert(i == len);
- if (active_index > 0) {
- SWAP(Base *, base_array[0], base_array[active_index]);
- }
+ BLI_assert(base_array[0] == baseact);
*r_len = len;
return base_array;
}
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index 94adba36664..d7b22b4f601 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -116,7 +116,7 @@ BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int off
BLI_INLINE bool metadata_is_custom_drawable(const char *field)
{
- /* Metadata field stored by Blender for multilayer EXR images. Is rather
+ /* Metadata field stored by Blender for multi-layer EXR images. Is rather
* useless to be viewed all the time. Can still be seen in the Metadata
* panel. */
if (STREQ(field, "BlenderMultiChannel")) {
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index 5b2e1a16bc2..06f1b999d58 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -92,7 +92,7 @@ static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op)
BKE_previewimg_id_custom_set(id, path);
- WM_event_add_notifier(C, NC_ASSET, nullptr);
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
return OPERATOR_FINISHED;
}
@@ -133,7 +133,7 @@ static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
}
UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
- WM_event_add_notifier(C, NC_ASSET, nullptr);
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 88802e0d868..f46975c9378 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -3313,7 +3313,6 @@ static bool do_lasso_select_mesh_uv(bContext *C,
uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
- /* don't indent to avoid diff noise! */
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
@@ -3323,7 +3322,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (use_face_center) { /* Face Center Sel */
+ if (use_face_center) { /* Face Center Select. */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
/* assume not touched */
@@ -3366,7 +3365,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
}
}
}
- else { /* Vert Sel */
+ else { /* Vert Selection. */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 429959f9c33..e4a0b154a07 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -27,7 +27,6 @@ set(INC_SYS
)
set(SRC
- intern/attributes_ref.cc
intern/cpp_types.cc
intern/multi_function.cc
intern/multi_function_builder.cc
@@ -36,7 +35,6 @@ set(SRC
intern/multi_function_network_optimization.cc
FN_array_spans.hh
- FN_attributes_ref.hh
FN_cpp_type.hh
FN_generic_pointer.hh
FN_generic_value_map.hh
@@ -63,7 +61,6 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
tests/FN_array_spans_test.cc
- tests/FN_attributes_ref_test.cc
tests/FN_cpp_type_test.cc
tests/FN_generic_vector_array_test.cc
tests/FN_multi_function_network_test.cc
diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh
deleted file mode 100644
index a9236f73549..00000000000
--- a/source/blender/functions/FN_attributes_ref.hh
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup fn
- *
- * An AttributesRef references multiple arrays of equal length. Each array has a corresponding name
- * and index.
- */
-
-#include <optional>
-
-#include "FN_spans.hh"
-
-#include "BLI_linear_allocator.hh"
-#include "BLI_map.hh"
-#include "BLI_utility_mixins.hh"
-#include "BLI_vector_set.hh"
-
-namespace blender::fn {
-
-class AttributesInfo;
-
-class AttributesInfoBuilder : NonCopyable, NonMovable {
- private:
- LinearAllocator<> allocator_;
- VectorSet<std::string> names_;
- Vector<const CPPType *> types_;
- Vector<void *> defaults_;
-
- friend AttributesInfo;
-
- public:
- AttributesInfoBuilder() = default;
- ~AttributesInfoBuilder();
-
- template<typename T> bool add(StringRef name, const T &default_value)
- {
- return this->add(name, CPPType::get<T>(), static_cast<const void *>(&default_value));
- }
-
- bool add(StringRef name, const CPPType &type, const void *default_value = nullptr);
-};
-
-/**
- * Stores which attributes are in an AttributesRef. Every attribute has a unique index, a unique
- * name, a type and a default value.
- */
-class AttributesInfo : NonCopyable, NonMovable {
- private:
- LinearAllocator<> allocator_;
- Map<StringRefNull, int> index_by_name_;
- Vector<StringRefNull> name_by_index_;
- Vector<const CPPType *> type_by_index_;
- Vector<void *> defaults_;
-
- public:
- AttributesInfo() = default;
- AttributesInfo(const AttributesInfoBuilder &builder);
- ~AttributesInfo();
-
- int size() const
- {
- return name_by_index_.size();
- }
-
- IndexRange index_range() const
- {
- return name_by_index_.index_range();
- }
-
- StringRefNull name_of(int index) const
- {
- return name_by_index_[index];
- }
-
- int index_of(StringRef name) const
- {
- return index_by_name_.lookup_as(name);
- }
-
- const void *default_of(int index) const
- {
- return defaults_[index];
- }
-
- const void *default_of(StringRef name) const
- {
- return this->default_of(this->index_of(name));
- }
-
- template<typename T> const T &default_of(int index) const
- {
- BLI_assert(type_by_index_[index]->is<T>());
- return *static_cast<T *>(defaults_[index]);
- }
-
- template<typename T> const T &default_of(StringRef name) const
- {
- return this->default_of<T>(this->index_of(name));
- }
-
- const CPPType &type_of(int index) const
- {
- return *type_by_index_[index];
- }
-
- const CPPType &type_of(StringRef name) const
- {
- return this->type_of(this->index_of(name));
- }
-
- bool has_attribute(StringRef name, const CPPType &type) const
- {
- return this->try_index_of(name, type) >= 0;
- }
-
- int try_index_of(StringRef name) const
- {
- return index_by_name_.lookup_default_as(name, -1);
- }
-
- int try_index_of(StringRef name, const CPPType &type) const
- {
- int index = this->try_index_of(name);
- if (index == -1) {
- return -1;
- }
- else if (this->type_of(index) == type) {
- return index;
- }
- else {
- return -1;
- }
- }
-};
-
-/**
- * References multiple arrays that match the description of an AttributesInfo instance. This class
- * is supposed to be relatively cheap to copy. It does not own any of the arrays itself.
- */
-class MutableAttributesRef {
- private:
- const AttributesInfo *info_;
- Span<void *> buffers_;
- IndexRange range_;
-
- friend class AttributesRef;
-
- public:
- MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, int64_t size)
- : MutableAttributesRef(info, buffers, IndexRange(size))
- {
- }
-
- MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, IndexRange range)
- : info_(&info), buffers_(buffers), range_(range)
- {
- }
-
- int64_t size() const
- {
- return range_.size();
- }
-
- IndexRange index_range() const
- {
- return IndexRange(this->size());
- }
-
- const AttributesInfo &info() const
- {
- return *info_;
- }
-
- GMutableSpan get(int index) const
- {
- const CPPType &type = info_->type_of(index);
- void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start());
- return GMutableSpan(type, ptr, range_.size());
- }
-
- GMutableSpan get(StringRef name) const
- {
- return this->get(info_->index_of(name));
- }
-
- template<typename T> MutableSpan<T> get(int index) const
- {
- BLI_assert(info_->type_of(index).is<T>());
- return MutableSpan<T>(static_cast<T *>(buffers_[index]) + range_.start(), range_.size());
- }
-
- template<typename T> MutableSpan<T> get(StringRef name) const
- {
- return this->get<T>(info_->index_of(name));
- }
-
- std::optional<GMutableSpan> try_get(StringRef name, const CPPType &type) const
- {
- int index = info_->try_index_of(name, type);
- if (index == -1) {
- return {};
- }
- else {
- return this->get(index);
- }
- }
-
- template<typename T> std::optional<MutableSpan<T>> try_get(StringRef name) const
- {
- int index = info_->try_index_of(name);
- if (index == -1) {
- return {};
- }
- else if (info_->type_of(index).is<T>()) {
- return this->get<T>(index);
- }
- else {
- return {};
- }
- }
-
- MutableAttributesRef slice(IndexRange range) const
- {
- return this->slice(range.start(), range.size());
- }
-
- MutableAttributesRef slice(int64_t start, int64_t size) const
- {
- return MutableAttributesRef(*info_, buffers_, range_.slice(start, size));
- }
-};
-
-class AttributesRef {
- private:
- const AttributesInfo *info_;
- Span<const void *> buffers_;
- IndexRange range_;
-
- public:
- AttributesRef(const AttributesInfo &info, Span<const void *> buffers, int64_t size)
- : AttributesRef(info, buffers, IndexRange(size))
- {
- }
-
- AttributesRef(const AttributesInfo &info, Span<const void *> buffers, IndexRange range)
- : info_(&info), buffers_(buffers), range_(range)
- {
- }
-
- AttributesRef(MutableAttributesRef attributes)
- : info_(attributes.info_), buffers_(attributes.buffers_), range_(attributes.range_)
- {
- }
-
- int64_t size() const
- {
- return range_.size();
- }
-
- const AttributesInfo &info() const
- {
- return *info_;
- }
-
- GSpan get(int index) const
- {
- const CPPType &type = info_->type_of(index);
- const void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start());
- return GSpan(type, ptr, range_.size());
- }
-
- GSpan get(StringRef name) const
- {
- return this->get(info_->index_of(name));
- }
-
- template<typename T> Span<T> get(int index) const
- {
- BLI_assert(info_->type_of(index).is<T>());
- return Span<T>(static_cast<T *>(buffers_[index]) + range_.start(), range_.size());
- }
-
- template<typename T> Span<T> get(StringRef name) const
- {
- return this->get<T>(info_->index_of(name));
- }
-
- std::optional<GSpan> try_get(StringRef name, const CPPType &type) const
- {
- int64_t index = info_->try_index_of(name, type);
- if (index == -1) {
- return {};
- }
- else {
- return this->get(index);
- }
- }
-
- template<typename T> std::optional<Span<T>> try_get(StringRef name) const
- {
- int index = info_->try_index_of(name);
- if (index == -1) {
- return {};
- }
- else if (info_->type_of(index).is<T>()) {
- return this->get<T>(index);
- }
- else {
- return {};
- }
- }
-
- AttributesRef slice(IndexRange range) const
- {
- return this->slice(range.start(), range.size());
- }
-
- AttributesRef slice(int64_t start, int64_t size) const
- {
- return AttributesRef(*info_, buffers_, range_.slice(start, size));
- }
-};
-
-} // namespace blender::fn
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index a854e63288d..b8ac97d6dbd 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -935,3 +935,9 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
{ \
return blender::fn::CPPType::get<TYPE_NAME>(); \
}
+
+/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */
+#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \
+ blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name(type.size(), \
+ type.alignment()); \
+ void *variable_name = stack_buffer_for_##variable_name.buffer();
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 6d5ca7f64ad..0cd1bc262be 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -170,6 +170,63 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
/**
* Generates a multi-function with the following parameters:
+ * 1. single input (SI) of type In1
+ * 2. single input (SI) of type In2
+ * 3. single input (SI) of type In3
+ * 4. single input (SI) of type In4
+ * 5. single output (SO) of type Out1
+ */
+template<typename In1, typename In2, typename In3, typename In4, typename Out1>
+class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
+ private:
+ using FunctionT = std::function<void(
+ IndexMask, VSpan<In1>, VSpan<In2>, VSpan<In3>, VSpan<In4>, MutableSpan<Out1>)>;
+ FunctionT function_;
+
+ public:
+ CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ {
+ MFSignatureBuilder signature = this->get_builder(name);
+ signature.single_input<In1>("In1");
+ signature.single_input<In2>("In2");
+ signature.single_input<In3>("In3");
+ signature.single_input<In4>("In4");
+ signature.single_output<Out1>("Out1");
+ }
+
+ template<typename ElementFuncT>
+ CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn))
+ {
+ }
+
+ template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
+ {
+ return [=](IndexMask mask,
+ VSpan<In1> in1,
+ VSpan<In2> in2,
+ VSpan<In3> in3,
+ VSpan<In4> in4,
+ MutableSpan<Out1> out1) {
+ mask.foreach_index([&](int i) {
+ new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i], in2[i], in3[i], in4[i]));
+ });
+ };
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ VSpan<In1> in1 = params.readonly_single_input<In1>(0);
+ VSpan<In2> in2 = params.readonly_single_input<In2>(1);
+ VSpan<In3> in3 = params.readonly_single_input<In3>(2);
+ VSpan<In4> in4 = params.readonly_single_input<In4>(3);
+ MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(4);
+ function_(mask, in1, in2, in3, in4, out1);
+ }
+};
+
+/**
+ * Generates a multi-function with the following parameters:
* 1. single mutable (SM) of type Mut1
*/
template<typename Mut1> class CustomMF_SM : public MultiFunction {
diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc
deleted file mode 100644
index 9f1e7fa65e5..00000000000
--- a/source/blender/functions/intern/attributes_ref.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "FN_attributes_ref.hh"
-
-namespace blender::fn {
-
-AttributesInfoBuilder::~AttributesInfoBuilder()
-{
- for (int i : defaults_.index_range()) {
- types_[i]->destruct(defaults_[i]);
- }
-}
-
-bool AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value)
-{
- if (name.size() == 0) {
- std::cout << "Warning: Tried to add an attribute with empty name.\n";
- return false;
- }
- if (names_.add_as(name)) {
- types_.append(&type);
-
- if (default_value == nullptr) {
- default_value = type.default_value();
- }
- void *dst = allocator_.allocate(type.size(), type.alignment());
- type.copy_to_uninitialized(default_value, dst);
- defaults_.append(dst);
- return true;
- }
-
- const CPPType &stored_type = *types_[names_.index_of_as(name)];
- if (stored_type != type) {
- std::cout << "Warning: Tried to add an attribute twice with different types (" << name << ": "
- << stored_type.name() << ", " << type.name() << ").\n";
- }
- return false;
-}
-
-AttributesInfo::AttributesInfo(const AttributesInfoBuilder &builder)
-{
- for (int i : builder.types_.index_range()) {
- StringRefNull name = allocator_.copy_string(builder.names_[i]);
- const CPPType &type = *builder.types_[i];
- const void *default_value = builder.defaults_[i];
-
- index_by_name_.add_new(name, i);
- name_by_index_.append(name);
- type_by_index_.append(&type);
-
- void *dst = allocator_.allocate(type.size(), type.alignment());
- type.copy_to_uninitialized(default_value, dst);
- defaults_.append(dst);
- }
-}
-
-AttributesInfo::~AttributesInfo()
-{
- for (int i : defaults_.index_range()) {
- type_by_index_[i]->destruct(defaults_[i]);
- }
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc
index 77c8ba6373f..b5c2c09a35a 100644
--- a/source/blender/functions/intern/multi_function_network.cc
+++ b/source/blender/functions/intern/multi_function_network.cc
@@ -70,7 +70,7 @@ MFFunctionNode &MFNetwork::add_function(const MultiFunction &function)
}
}
- MFFunctionNode &node = *allocator_.construct<MFFunctionNode>();
+ MFFunctionNode &node = *allocator_.construct<MFFunctionNode>().release();
function_nodes_.add_new(&node);
node.network_ = this;
@@ -129,7 +129,7 @@ MFDummyNode &MFNetwork::add_dummy(StringRef name,
assert_same_size(input_types, input_names);
assert_same_size(output_types, output_names);
- MFDummyNode &node = *allocator_.construct<MFDummyNode>();
+ MFDummyNode &node = *allocator_.construct<MFDummyNode>().release();
dummy_nodes_.add_new(&node);
node.network_ = this;
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index c543d86ad34..5a37a45908f 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -663,7 +663,7 @@ void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSock
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(virtual_span.size() >= min_array_size_);
- auto *value = allocator_.construct<InputSingleValue>(virtual_span);
+ auto *value = allocator_.construct<InputSingleValue>(virtual_span).release();
value_per_output_id_[socket.id()] = value;
}
@@ -673,7 +673,7 @@ void MFNetworkEvaluationStorage::add_vector_input_from_caller(const MFOutputSock
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(virtual_array_span.size() >= min_array_size_);
- auto *value = allocator_.construct<InputVectorValue>(virtual_array_span);
+ auto *value = allocator_.construct<InputVectorValue>(virtual_array_span).release();
value_per_output_id_[socket.id()] = value;
}
@@ -683,7 +683,7 @@ void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSoc
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(span.size() >= min_array_size_);
- auto *value = allocator_.construct<OutputSingleValue>(span);
+ auto *value = allocator_.construct<OutputSingleValue>(span).release();
value_per_output_id_[socket.id()] = value;
}
@@ -693,7 +693,7 @@ void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSoc
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(vector_array.size() >= min_array_size_);
- auto *value = allocator_.construct<OutputVectorValue>(vector_array);
+ auto *value = allocator_.construct<OutputVectorValue>(vector_array).release();
value_per_output_id_[socket.id()] = value;
}
@@ -705,7 +705,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputS
void *buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT);
GMutableSpan span(type, buffer, min_array_size_);
- auto *value = allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false);
+ auto *value =
+ allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false).release();
value_per_output_id_[socket.id()] = value;
return span;
@@ -723,7 +724,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutpu
void *buffer = allocator_.allocate(type.size(), type.alignment());
GMutableSpan span(type, buffer, 1);
- auto *value = allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true);
+ auto *value =
+ allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true).release();
value_per_output_id_[socket.id()] = value;
return value->span;
@@ -742,7 +744,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutput
const CPPType &type = socket.data_type().vector_base_type();
GVectorArray *vector_array = new GVectorArray(type, min_array_size_);
- auto *value = allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size());
+ auto *value =
+ allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release();
value_per_output_id_[socket.id()] = value;
return *value->vector_array;
@@ -759,7 +762,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutp
const CPPType &type = socket.data_type().vector_base_type();
GVectorArray *vector_array = new GVectorArray(type, 1);
- auto *value = allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size());
+ auto *value =
+ allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release();
value_per_output_id_[socket.id()] = value;
return *value->vector_array;
@@ -806,8 +810,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
GMutableSpan new_array_ref(type, new_buffer, min_array_size_);
virtual_span.materialize_to_uninitialized(mask_, new_array_ref.data());
- OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>(
- new_array_ref, to.targets().size(), false);
+ OwnSingleValue *new_value =
+ allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), false).release();
value_per_output_id_[to.id()] = new_value;
return new_array_ref;
}
@@ -850,8 +854,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu
type.copy_to_uninitialized(virtual_span.as_single_element(), new_buffer);
GMutableSpan new_array_ref(type, new_buffer, 1);
- OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>(
- new_array_ref, to.targets().size(), true);
+ OwnSingleValue *new_value =
+ allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), true).release();
value_per_output_id_[to.id()] = new_value;
return new_array_ref;
}
@@ -891,8 +895,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput
GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_);
new_vector_array->extend(mask_, virtual_array_span);
- OwnVectorValue *new_value = allocator_.construct<OwnVectorValue>(*new_vector_array,
- to.targets().size());
+ OwnVectorValue *new_value =
+ allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
value_per_output_id_[to.id()] = new_value;
return *new_vector_array;
@@ -934,8 +938,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp
GVectorArray *new_vector_array = new GVectorArray(base_type, 1);
new_vector_array->extend(0, virtual_array_span[0]);
- OwnVectorValue *new_value = allocator_.construct<OwnVectorValue>(*new_vector_array,
- to.targets().size());
+ OwnVectorValue *new_value =
+ allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
value_per_output_id_[to.id()] = new_value;
return *new_vector_array;
}
diff --git a/source/blender/functions/tests/FN_attributes_ref_test.cc b/source/blender/functions/tests/FN_attributes_ref_test.cc
deleted file mode 100644
index 3a5e4743c1e..00000000000
--- a/source/blender/functions/tests/FN_attributes_ref_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Apache License, Version 2.0 */
-
-#include "BLI_float3.hh"
-#include "FN_attributes_ref.hh"
-
-#include "testing/testing.h"
-
-namespace blender::fn::tests {
-
-TEST(attributes_info, BuildEmpty)
-{
- AttributesInfoBuilder info_builder;
- AttributesInfo info{info_builder};
-
- EXPECT_EQ(info.size(), 0);
-}
-
-TEST(attributes_info, AddSameNameTwice)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add<int>("A", 4);
- info_builder.add<int>("A", 5);
- AttributesInfo info{info_builder};
- EXPECT_EQ(info.size(), 1);
- EXPECT_TRUE(info.has_attribute("A", CPPType::get<int>()));
- EXPECT_FALSE(info.has_attribute("B", CPPType::get<int>()));
- EXPECT_FALSE(info.has_attribute("A", CPPType::get<float>()));
- EXPECT_EQ(info.default_of<int>("A"), 4);
- EXPECT_EQ(info.name_of(0), "A");
- EXPECT_EQ(info.index_range().start(), 0);
- EXPECT_EQ(info.index_range().one_after_last(), 1);
-}
-
-TEST(attributes_info, BuildWithDefaultString)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add("A", CPPType::get<std::string>());
- AttributesInfo info{info_builder};
- EXPECT_EQ(info.default_of<std::string>("A"), "");
-}
-
-TEST(attributes_info, BuildWithGivenDefault)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add<std::string>("A", "hello world");
- AttributesInfo info{info_builder};
- const void *default_value = info.default_of("A");
- EXPECT_EQ(*(const std::string *)default_value, "hello world");
- EXPECT_EQ(info.type_of("A"), CPPType::get<std::string>());
-}
-
-TEST(mutable_attributes_ref, ComplexTest)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add<float3>("Position", {0, 0, 10});
- info_builder.add<uint>("ID", 0);
- info_builder.add<float>("Size", 0.5f);
- info_builder.add<std::string>("Name", "<no name>");
- AttributesInfo info{info_builder};
-
- int amount = 5;
- Array<float3> positions(amount);
- Array<uint> ids(amount, 0);
- Array<float> sizes(amount);
- Array<std::string> names(amount);
-
- Array<void *> buffers = {positions.data(), ids.data(), sizes.data(), names.data()};
- MutableAttributesRef attributes{info, buffers, IndexRange(1, 3)};
- EXPECT_EQ(attributes.size(), 3);
- EXPECT_EQ(attributes.info().size(), 4);
- EXPECT_EQ(attributes.get("Position").data(), positions.data() + 1);
- EXPECT_EQ(attributes.get("ID").data(), ids.data() + 1);
- EXPECT_EQ(attributes.get("Size").data(), sizes.data() + 1);
- EXPECT_EQ(attributes.get("Name").data(), names.data() + 1);
-
- EXPECT_EQ(attributes.get("ID").size(), 3);
- EXPECT_EQ(attributes.get<uint>("ID").size(), 3);
-
- EXPECT_EQ(ids[2], 0);
- MutableSpan<uint> ids_span = attributes.get<uint>("ID");
- ids_span[1] = 42;
- EXPECT_EQ(ids[2], 42);
-
- EXPECT_FALSE(attributes.try_get<int>("not existant").has_value());
- EXPECT_FALSE(attributes.try_get<int>("Position").has_value());
- EXPECT_TRUE(attributes.try_get<float3>("Position").has_value());
- EXPECT_FALSE(attributes.try_get("not existant", CPPType::get<int>()).has_value());
- EXPECT_FALSE(attributes.try_get("Position", CPPType::get<int>()).has_value());
- EXPECT_TRUE(attributes.try_get("Position", CPPType::get<float3>()).has_value());
-
- MutableAttributesRef sliced = attributes.slice(IndexRange(1, 2));
- EXPECT_EQ(sliced.size(), 2);
- sliced.get<uint>("ID")[0] = 100;
- EXPECT_EQ(ids[2], 100);
-}
-
-} // namespace blender::fn::tests
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 9f1484b47c0..e3bb0d773a2 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
intern/MOD_gpencilbuild.c
intern/MOD_gpencilcolor.c
intern/MOD_gpencilhook.c
+ intern/MOD_gpencillineart.c
intern/MOD_gpencillattice.c
intern/MOD_gpencilmirror.c
intern/MOD_gpencilmultiply.c
@@ -70,6 +71,16 @@ set(SRC
MOD_gpencil_modifiertypes.h
intern/MOD_gpencil_ui_common.h
intern/MOD_gpencil_util.h
+
+ # Lineart code
+ intern/lineart/lineart_ops.c
+ intern/lineart/lineart_cpu.c
+ intern/lineart/lineart_chain.c
+ intern/lineart/lineart_util.c
+
+ intern/lineart/lineart_intern.h
+ intern/lineart/MOD_lineart.h
+
)
set(LIB
@@ -79,6 +90,7 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
new file mode 100644
index 00000000000..685f0cb36cb
--- /dev/null
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
@@ -0,0 +1,31 @@
+/*
+ * 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 modifiers
+ */
+
+#pragma once
+
+#include "DNA_windowmanager_types.h"
+
+/* Operator types should be in exposed header. */
+void OBJECT_OT_lineart_bake_strokes(struct wmOperatorType *ot);
+void OBJECT_OT_lineart_bake_strokes_all(struct wmOperatorType *ot);
+void OBJECT_OT_lineart_clear(struct wmOperatorType *ot);
+void OBJECT_OT_lineart_clear_all(struct wmOperatorType *ot);
+
+void WM_operatortypes_lineart(void);
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index 3f167ac6785..e6ce7983a0f 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -43,6 +43,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Armature;
extern GpencilModifierTypeInfo modifierType_Gpencil_Time;
extern GpencilModifierTypeInfo modifierType_Gpencil_Multiply;
extern GpencilModifierTypeInfo modifierType_Gpencil_Texture;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Lineart;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index 05e7a23bc82..10383a9417d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -371,14 +371,9 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw)
{
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- /* Get the name for the modifier's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- BKE_gpencil_modifierType_panel_id(type, panel_idname);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BKE_gpencil_modifierType_panel_id(type, panel_type->idname);
BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -412,13 +407,9 @@ PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type,
PanelDrawFn draw,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index f5bfe66562b..beb32c7a38e 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -74,6 +74,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Time);
INIT_GP_TYPE(Multiply);
INIT_GP_TYPE(Texture);
+ INIT_GP_TYPE(Lineart);
#undef INIT_GP_TYPE
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index cc8eae64300..f021f71dbdc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -179,7 +179,9 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
return !mmd->object || mmd->object->type != OB_ARMATURE;
}
-static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
{
ArmatureGpencilModifierData *lmd = (ArmatureGpencilModifierData *)md;
if (lmd->object != NULL) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index b8fa88327fc..7aa1320c4e3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -318,7 +318,9 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
generate_geometry(md, depsgraph, scene, ob);
}
-static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
{
ArrayGpencilModifierData *lmd = (ArrayGpencilModifierData *)md;
if (lmd->object != NULL) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index 09cce3f1ab4..e0300eb498f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -330,7 +330,9 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
return !mmd->object;
}
-static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
{
HookGpencilModifierData *lmd = (HookGpencilModifierData *)md;
if (lmd->object != NULL) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index b2a83e83c9e..7d78892aa6b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -195,7 +195,9 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
return !mmd->object || mmd->object->type != OB_LATTICE;
}
-static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
{
LatticeGpencilModifierData *lmd = (LatticeGpencilModifierData *)md;
if (lmd->object != NULL) {
@@ -265,7 +267,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
/* structName */ "LatticeGpencilModifierData",
/* structSize */ sizeof(LatticeGpencilModifierData),
/* type */ eGpencilModifierTypeType_Gpencil,
- /* flags */ eGpencilModifierTypeFlag_Single | eGpencilModifierTypeFlag_SupportsEditmode,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
new file mode 100644
index 00000000000..2170e486416
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -0,0 +1,501 @@
+/*
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_defaults.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lineart_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "lineart/MOD_lineart.h"
+
+#include "BKE_collection.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_modifier.h"
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_ui_common.h"
+#include "MOD_gpencil_util.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+static void initData(GpencilModifierData *md)
+{
+ LineartGpencilModifierData *gpmd = (LineartGpencilModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(LineartGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static void generate_strokes_actual(
+ GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+
+ if (G.debug_value == 4000) {
+ printf("LRT: Generating from modifier.\n");
+ }
+
+ MOD_lineart_gpencil_generate(
+ lmd->render_buffer,
+ depsgraph,
+ ob,
+ gpl,
+ gpf,
+ lmd->source_type,
+ lmd->source_type == LRT_SOURCE_OBJECT ? (void *)lmd->source_object :
+ (void *)lmd->source_collection,
+ lmd->level_start,
+ lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
+ lmd->target_material ? BKE_gpencil_object_material_index_get(ob, lmd->target_material) : 0,
+ lmd->line_types,
+ lmd->transparency_flags,
+ lmd->transparency_mask,
+ lmd->thickness,
+ lmd->opacity,
+ lmd->pre_sample_length,
+ lmd->source_vertex_group,
+ lmd->vgname,
+ lmd->flags);
+}
+
+static bool isModifierDisabled(GpencilModifierData *md)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+
+ if ((lmd->target_layer[0] == '\0') || (lmd->target_material == NULL)) {
+ return true;
+ }
+
+ if (lmd->source_type == LRT_SOURCE_OBJECT && !lmd->source_object) {
+ return true;
+ }
+
+ if (lmd->source_type == LRT_SOURCE_COLLECTION && !lmd->source_collection) {
+ return true;
+ }
+
+ /* Preventing calculation in depsgraph when baking frames. */
+ if (lmd->flags & LRT_GPENCIL_IS_BAKED) {
+ return true;
+ }
+
+ return false;
+}
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ /* Guard early, don't trigger calculation when no gpencil frame is present. Probably should
+ * disable in the isModifierDisabled() function but we need addtional arg for depsgraph and
+ * gpd. */
+ bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
+ if (gpl == NULL) {
+ return;
+ }
+ /* Need to call this or we don't get active frame (user may haven't selected any one). */
+ BKE_gpencil_frame_active_set(depsgraph, gpd);
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ BKE_gpencil_frame_addnew(gpl, DEG_get_evaluated_scene(depsgraph)->r.cfra);
+ return;
+ }
+
+ /* Check all parameters required are filled. */
+ if (isModifierDisabled(md)) {
+ return;
+ }
+
+ MOD_lineart_compute_feature_lines(depsgraph, lmd);
+
+ generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
+
+ MOD_lineart_destroy_render_data(lmd);
+
+ WM_main_add_notifier(NA_EDITED | NC_GPENCIL, NULL);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ bGPdata *gpd = ob->data;
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+
+ bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
+ if (gpl == NULL) {
+ return;
+ }
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ return;
+ }
+
+ MOD_lineart_compute_feature_lines(depsgraph, lmd);
+
+ generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
+
+ MOD_lineart_destroy_render_data(lmd);
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ return isModifierDisabled(md);
+}
+
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int mode)
+{
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ if (lmd->source_type == LRT_SOURCE_OBJECT && lmd->source_object) {
+ DEG_add_object_relation(
+ ctx->node, lmd->source_object, DEG_OB_COMP_GEOMETRY, "Line Art Modifier");
+ DEG_add_object_relation(
+ ctx->node, lmd->source_object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+ }
+ else {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->scene->master_collection, ob, mode) {
+ if (ob->type == OB_MESH || ob->type == OB_MBALL || ob->type == OB_CURVE ||
+ ob->type == OB_SURF || ob->type == OB_FONT) {
+ if (!(ob->lineart.usage & COLLECTION_LRT_EXCLUDE)) {
+ DEG_add_object_relation(ctx->node, ob, DEG_OB_COMP_GEOMETRY, "Line Art Modifier");
+ DEG_add_object_relation(ctx->node, ob, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+ }
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ DEG_add_object_relation(
+ ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&lmd->target_material, IDWALK_CB_USER);
+ walk(userData, ob, (ID **)&lmd->source_collection, IDWALK_CB_NOP);
+
+ walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
+
+ const int source_type = RNA_enum_get(ptr, "source_type");
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ uiItemR(layout, ptr, "source_type", 0, NULL, ICON_NONE);
+
+ if (source_type == LRT_SOURCE_OBJECT) {
+ uiItemR(layout, ptr, "source_object", 0, NULL, ICON_OBJECT_DATA);
+ }
+ else if (source_type == LRT_SOURCE_COLLECTION) {
+ uiItemR(layout, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION);
+ }
+ else {
+ /* Source is Scene. */
+ }
+
+ uiLayout *col = uiLayoutColumnWithHeading(layout, true, IFACE_("Edge Types"));
+
+ uiItemR(col, ptr, "use_contour", 0, IFACE_("Contour"), ICON_NONE);
+ uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
+ uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
+ uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
+ uiItemR(col, ptr, "use_crease", 0, IFACE_("Crease"), ICON_NONE);
+ uiLayout *sub = uiLayoutRow(col, true);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_crease"));
+ uiLayoutSetPropSep(sub, true);
+
+ uiItemR(sub, ptr, "crease_threshold", UI_ITEM_R_SLIDER, " ", ICON_NONE);
+
+ uiItemPointerR(layout, ptr, "target_layer", &obj_data_ptr, "layers", NULL, ICON_GREASEPENCIL);
+ uiItemPointerR(
+ layout, ptr, "target_material", &obj_data_ptr, "materials", NULL, ICON_SHADING_TEXTURE);
+
+ uiItemR(layout, ptr, "remove_doubles", 0, NULL, ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "allow_overlapping_edges",
+ 0,
+ IFACE_("Overlapping Edges As Contour"),
+ ICON_NONE);
+
+ gpencil_modifier_panel_end(layout, ptr);
+}
+
+static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ uiItemR(layout, ptr, "thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+}
+
+static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
+
+ uiItemR(layout, ptr, "use_multiple_levels", 0, IFACE_("Range"), ICON_NONE);
+
+ if (use_multiple_levels) {
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "level_start", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "level_end", 0, NULL, ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "level_start", 0, IFACE_("Level"), ICON_NONE);
+ }
+}
+
+static void transparency_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ uiItemR(layout, ptr, "use_transparency", 0, IFACE_("Transparency"), ICON_NONE);
+}
+
+static void transparency_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_transparency"));
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiLayoutSetPropDecorate(row, false);
+ uiLayout *sub = uiLayoutRow(row, true);
+ uiItemR(sub, ptr, "transparency_mask_0", UI_ITEM_R_TOGGLE, IFACE_("0"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_1", UI_ITEM_R_TOGGLE, IFACE_("1"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_2", UI_ITEM_R_TOGGLE, IFACE_("2"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_3", UI_ITEM_R_TOGGLE, IFACE_("3"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_4", UI_ITEM_R_TOGGLE, IFACE_("4"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_5", UI_ITEM_R_TOGGLE, IFACE_("5"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_6", UI_ITEM_R_TOGGLE, IFACE_("6"), ICON_NONE);
+ uiItemR(sub, ptr, "transparency_mask_7", UI_ITEM_R_TOGGLE, IFACE_("7"), ICON_NONE);
+ uiItemL(row, "", ICON_BLANK1); /* Space for decorator. */
+
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "transparency_match", 0, IFACE_("Match All Masks"), ICON_NONE);
+}
+
+static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayout *layout = panel->layout;
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ uiLayout *col = uiLayoutColumnWithHeading(layout, true, IFACE_("Chain"));
+ uiItemR(col, ptr, "fuzzy_intersections", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "fuzzy_everything", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "chaining_geometry_threshold", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "chaining_image_threshold", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "pre_sample_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "angle_splitting_threshold", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+}
+
+static void vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ uiLayout *layout = panel->layout;
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ uiLayout *col = uiLayoutColumn(layout, true);
+
+ uiLayout *row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "source_vertex_group", 0, IFACE_("Filter Source"), ICON_GROUP_VERTEX);
+ uiItemR(row, ptr, "invert_source_vertex_group", UI_ITEM_R_TOGGLE, "", ICON_ARROW_LEFTRIGHT);
+
+ uiItemR(col, ptr, "match_output_vertex_group", 0, NULL, ICON_NONE);
+
+ const bool match_output = RNA_boolean_get(ptr, "match_output_vertex_group");
+ if (!match_output) {
+ uiItemPointerR(
+ col, ptr, "vertex_group", &ob_ptr, "vertex_groups", IFACE_("Target"), ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "soft_selection", 0, NULL, ICON_NONE);
+}
+
+static void baking_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+
+ uiLayoutSetPropSep(layout, true);
+
+ if (is_baked) {
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayoutSetPropSep(col, false);
+ uiItemL(col, IFACE_("Modifier has baked data."), ICON_NONE);
+ uiItemR(
+ col, ptr, "is_baked", UI_ITEM_R_TOGGLE, IFACE_("Continue Without Clearing"), ICON_NONE);
+ }
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayoutSetEnabled(col, !is_baked);
+ uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_bake_strokes");
+ uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_bake_strokes_all");
+
+ col = uiLayoutColumn(layout, false);
+ uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear");
+ uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear_all");
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ PanelType *panel_type = gpencil_modifier_panel_register(
+ region_type, eGpencilModifierType_Lineart, panel_draw);
+
+ gpencil_modifier_subpanel_register(
+ region_type, "style", "Style", NULL, style_panel_draw, panel_type);
+ PanelType *occlusion_panel = gpencil_modifier_subpanel_register(
+ region_type, "occlusion", "Occlusion", NULL, occlusion_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(region_type,
+ "transparency",
+ "",
+ transparency_panel_draw_header,
+ transparency_panel_draw,
+ occlusion_panel);
+ gpencil_modifier_subpanel_register(
+ region_type, "chaining", "Chaining", NULL, chaining_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
+ region_type, "vgroup", "Vertex Weight Transfer", NULL, vgroup_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
+ region_type, "baking", "Baking", NULL, baking_panel_draw, panel_type);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Lineart = {
+ /* name. */ "Line Art",
+ /* structName. */ "LineartGpencilModifierData",
+ /* structSize. */ sizeof(LineartGpencilModifierData),
+ /* type. */ eGpencilModifierTypeType_Gpencil,
+ /* flags. */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData. */ copyData,
+
+ /* deformStroke. */ NULL,
+ /* generateStrokes. */ generateStrokes,
+ /* bakeModifier. */ bakeModifier,
+ /* remapTime. */ NULL,
+
+ /* initData. */ initData,
+ /* freeData. */ NULL,
+ /* isDisabled. */ isDisabled,
+ /* updateDepsgraph. */ updateDepsgraph,
+ /* dependsOnTime. */ NULL,
+ /* foreachIDLink. */ foreachIDLink,
+ /* foreachTexLink. */ NULL,
+ /* panelRegister. */ panelRegister,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 111c60436bf..eec4eab3441 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -207,7 +207,9 @@ static bool isDisabled(GpencilModifierData *UNUSED(md), int UNUSED(userRenderPar
return false;
}
-static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
{
MirrorGpencilModifierData *lmd = (MirrorGpencilModifierData *)md;
if (lmd->object != NULL) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index 311d08238b9..fcc0a1f35eb 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -311,7 +311,9 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
return !mmd->object;
}
-static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
{
TintGpencilModifierData *lmd = (TintGpencilModifierData *)md;
if (lmd->object != NULL) {
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
new file mode 100644
index 00000000000..0c170deacbb
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -0,0 +1,552 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#pragma once
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "DNA_lineart_types.h"
+
+#include <math.h>
+#include <string.h>
+
+typedef struct LineartStaticMemPoolNode {
+ Link item;
+ size_t size;
+ size_t used_byte;
+ /* User memory starts here */
+} LineartStaticMemPoolNode;
+
+typedef struct LineartStaticMemPool {
+ ListBase pools;
+ SpinLock lock_mem;
+} LineartStaticMemPool;
+
+typedef struct LineartTriangleAdjacent {
+ struct LineartLine *rl[3];
+} LineartTriangleAdjacent;
+
+typedef struct LineartTriangle {
+ struct LineartVert *v[3];
+
+ /* first culled in line list to use adjacent triangle info, then go through triangle list. */
+ double gn[3];
+
+ /* Material flag is removed to save space. */
+ unsigned char transparency_mask;
+ unsigned char flags; /* eLineartTriangleFlags */
+
+ /* Only use single link list, because we don't need to go back in order.
+ * This variable is also reused to store the pointer to adjacent lines of this triangle before
+ * intersection statge */
+ struct LinkNode *intersecting_verts;
+} LineartTriangle;
+
+typedef struct LineartTriangleThread {
+ struct LineartTriangle base;
+ /* This variable is used to store per-thread triangle-line testing pair,
+ * also re-used to store triangle-triangle pair for intersection testing stage.
+ * Do not directly use LineartTriangleThread.
+ * The size of LineartTriangle is dynamically allocated to contain set thread number of
+ * "testing" field. Worker threads will test lines against the "base" triangle.
+ * At least one thread is present, thus we always have at least testing[0]. */
+ struct LineartLine *testing[1];
+} LineartTriangleThread;
+
+typedef enum eLineArtElementNodeFlag {
+ LRT_ELEMENT_IS_ADDITIONAL = (1 << 0),
+ LRT_ELEMENT_BORDER_ONLY = (1 << 1),
+ LRT_ELEMENT_NO_INTERSECTION = (1 << 2),
+} eLineArtElementNodeFlag;
+
+typedef struct LineartElementLinkNode {
+ struct LineartElementLinkNode *next, *prev;
+ void *pointer;
+ int element_count;
+ void *object_ref;
+ eLineArtElementNodeFlag flags;
+
+ /* Per object value, always set, if not enabled by ObjectLineArt, then it's set to global. */
+ float crease_threshold;
+} LineartElementLinkNode;
+
+typedef struct LineartLineSegment {
+ struct LineartLineSegment *next, *prev;
+ /** at==0: left at==1: right (this is in 2D projected space) */
+ double at;
+ /** Occlusion level after "at" point */
+ unsigned char occlusion;
+
+ /** For determining lines beind a glass window material.
+ * the size of this variable should also be dynamically decided, 1 byte to 8 byte,
+ * allows 8 to 64 materials for "transparent mask". 1 byte (8 materials) should be
+ * enought for most cases.
+ */
+ unsigned char transparency_mask;
+} LineartLineSegment;
+
+typedef struct LineartVert {
+ double gloc[3];
+ double fbcoord[4];
+
+ /* Scene global index. */
+ int index;
+
+ /** Intersection data flag is here, when LRT_VERT_HAS_INTERSECTION_DATA is set,
+ * size of the struct is extended to include intersection data.
+ * See eLineArtVertFlags.
+ */
+ char flag;
+
+} LineartVert;
+
+typedef struct LineartVertIntersection {
+ struct LineartVert base;
+ /* Use vert index because we only use this to check vertex equal. This way we save 8 Bytes. */
+ int isec1, isec2;
+ struct LineartTriangle *intersecting_with;
+} LineartVertIntersection;
+
+typedef enum eLineArtVertFlags {
+ LRT_VERT_HAS_INTERSECTION_DATA = (1 << 0),
+ LRT_VERT_EDGE_USED = (1 << 1),
+} eLineArtVertFlags;
+
+typedef struct LineartLine {
+ /* We only need link node kind of list here. */
+ struct LineartLine *next;
+ struct LineartVert *l, *r;
+ /* Local vertex index for two ends, not puting in RenderVert because all verts are loaded, so as
+ * long as fewer than half of the mesh edges are becoming a feature line, we save more memory. */
+ int l_obindex, r_obindex;
+ struct LineartTriangle *tl, *tr;
+ ListBase segments;
+ char min_occ;
+
+ /** Also for line type determination on chainning */
+ unsigned char flags;
+
+ /** Still need this entry because culled lines will not add to object reln node,
+ * TODO: If really need more savings, we can allocate this in a "extended" way too, but we need
+ * another bit in flags to be able to show the difference.
+ */
+ struct Object *object_ref;
+} LineartLine;
+
+typedef struct LineartLineChain {
+ struct LineartLineChain *next, *prev;
+ ListBase chain;
+
+ /** Calculated before draw cmd. */
+ float length;
+
+ /** Used when re-connecting and gp stroke generation */
+ char picked;
+ char level;
+
+ /** Chain now only contains one type of segments */
+ int type;
+ unsigned char transparency_mask;
+
+ struct Object *object_ref;
+} LineartLineChain;
+
+typedef struct LineartLineChainItem {
+ struct LineartLineChainItem *next, *prev;
+ /** Need z value for fading */
+ float pos[3];
+ /** For restoring position to 3d space */
+ float gpos[3];
+ float normal[3];
+ char line_type;
+ char occlusion;
+ unsigned char transparency_mask;
+ size_t index;
+} LineartLineChainItem;
+
+typedef struct LineartChainRegisterEntry {
+ struct LineartChainRegisterEntry *next, *prev;
+ LineartLineChain *rlc;
+ LineartLineChainItem *rlci;
+ char picked;
+
+ /** left/right mark.
+ * Because we revert list in chaining so we need the flag. */
+ char is_left;
+} LineartChainRegisterEntry;
+
+typedef struct LineartRenderBuffer {
+ struct LineartRenderBuffer *prev, *next;
+
+ int thread_count;
+
+ int w, h;
+ int tile_size_w, tile_size_h;
+ int tile_count_x, tile_count_y;
+ double width_per_tile, height_per_tile;
+ double view_projection[4][4];
+
+ struct LineartBoundingArea *initial_bounding_areas;
+ unsigned int bounding_area_count;
+
+ ListBase vertex_buffer_pointers;
+ ListBase line_buffer_pointers;
+ ListBase triangle_buffer_pointers;
+
+ /* This one's memory is not from main pool and is free()ed after culling stage. */
+ ListBase triangle_adjacent_pointers;
+
+ ListBase intersecting_vertex_buffer;
+ /** Use the one comes with Line Art. */
+ LineartStaticMemPool render_data_pool;
+ ListBase wasted_cuts;
+ SpinLock lock_cuts;
+
+ /* Render status */
+ double view_vector[3];
+
+ int triangle_size;
+
+ unsigned int contour_count;
+ unsigned int contour_processed;
+ LineartLine *contour_managed;
+ /* Now changed to linknodes. */
+ LineartLine *contours;
+
+ unsigned int intersection_count;
+ unsigned int intersection_processed;
+ LineartLine *intersection_managed;
+ LineartLine *intersection_lines;
+
+ unsigned int crease_count;
+ unsigned int crease_processed;
+ LineartLine *crease_managed;
+ LineartLine *crease_lines;
+
+ unsigned int material_line_count;
+ unsigned int material_processed;
+ LineartLine *material_managed;
+ LineartLine *material_lines;
+
+ unsigned int edge_mark_count;
+ unsigned int edge_mark_processed;
+ LineartLine *edge_mark_managed;
+ LineartLine *edge_marks;
+
+ ListBase chains;
+
+ /** For managing calculation tasks for multiple threads. */
+ SpinLock lock_task;
+
+ /* settings */
+
+ int max_occlusion_level;
+ double crease_angle;
+ double crease_cos;
+
+ int draw_material_preview;
+ double material_transparency;
+
+ bool use_contour;
+ bool use_crease;
+ bool use_material;
+ bool use_edge_marks;
+ bool use_intersections;
+ bool fuzzy_intersections;
+ bool fuzzy_everything;
+ bool allow_boundaries;
+ bool allow_overlapping_edges;
+ bool remove_doubles;
+
+ /** Keep an copy of these data so when line art is running it's self-contained. */
+ bool cam_is_persp;
+ float cam_obmat[4][4];
+ double camera_pos[3];
+ double near_clip, far_clip;
+ float shift_x, shift_y;
+ float crease_threshold;
+ float chaining_image_threshold;
+ float chaining_geometry_threshold;
+ float angle_splitting_threshold;
+} LineartRenderBuffer;
+
+#define DBL_TRIANGLE_LIM 1e-8
+#define DBL_EDGE_LIM 1e-9
+
+#define LRT_MEMORY_POOL_64MB (1 << 26)
+
+typedef enum eLineartTriangleFlags {
+ LRT_CULL_DONT_CARE = 0,
+ LRT_CULL_USED = (1 << 0),
+ LRT_CULL_DISCARD = (1 << 1),
+ LRT_CULL_GENERATED = (1 << 2),
+ LRT_TRIANGLE_INTERSECTION_ONLY = (1 << 3),
+ LRT_TRIANGLE_NO_INTERSECTION = (1 << 4),
+} eLineartTriangleFlags;
+
+/** Controls how many lines a worker thread is processing at one request.
+ * There's no significant performance impact on choosing different values.
+ * Don't make it too small so that the worker thread won't request too many times. */
+#define LRT_THREAD_LINE_COUNT 1000
+
+typedef struct LineartRenderTaskInfo {
+ struct LineartRenderBuffer *rb;
+
+ int thread_id;
+
+ LineartLine *contour;
+ LineartLine *contour_end;
+
+ LineartLine *intersection;
+ LineartLine *intersection_end;
+
+ LineartLine *crease;
+ LineartLine *crease_end;
+
+ LineartLine *material;
+ LineartLine *material_end;
+
+ LineartLine *edge_mark;
+ LineartLine *edge_mark_end;
+
+} LineartRenderTaskInfo;
+
+/** Bounding area diagram:
+ *
+ * +----+ <----U (Upper edge Y value)
+ * | |
+ * +----+ <----B (Bottom edge Y value)
+ * ^ ^
+ * L R (Left/Right edge X value)
+ *
+ * Example structure when subdividing 1 bounding areas:
+ * 1 area can be divided into 4 smaller children to
+ * accomodate image areas with denser triangle distribution.
+ * +--+--+-----+
+ * +--+--+ |
+ * +--+--+-----+
+ * | | |
+ * +-----+-----+
+ * lp/rp/up/bp is the list for
+ * storing pointers to adjacent bounding areas.
+ */
+typedef struct LineartBoundingArea {
+ double l, r, u, b;
+ double cx, cy;
+
+ /** 1,2,3,4 quadrant */
+ struct LineartBoundingArea *child;
+
+ ListBase lp;
+ ListBase rp;
+ ListBase up;
+ ListBase bp;
+
+ short triangle_count;
+
+ ListBase linked_triangles;
+ ListBase linked_lines;
+
+ /** Reserved for image space reduction && multithread chainning */
+ ListBase linked_chains;
+} LineartBoundingArea;
+
+#define LRT_TILE(tile, r, c, CCount) tile[r * CCount + c]
+
+#define LRT_CLAMP(a, Min, Max) a = a < Min ? Min : (a > Max ? Max : a)
+
+#define LRT_MAX3_INDEX(a, b, c) (a > b ? (a > c ? 0 : (b > c ? 1 : 2)) : (b > c ? 1 : 2))
+
+#define LRT_MIN3_INDEX(a, b, c) (a < b ? (a < c ? 0 : (b < c ? 1 : 2)) : (b < c ? 1 : 2))
+
+#define LRT_MAX3_INDEX_ABC(x, y, z) (x > y ? (x > z ? a : (y > z ? b : c)) : (y > z ? b : c))
+
+#define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
+
+#define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c))
+
+#define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
+
+BLI_INLINE int lineart_LineIntersectTest2d(
+ const double *a1, const double *a2, const double *b1, const double *b2, double *aRatio)
+{
+#define USE_VECTOR_LINE_INTERSECTION
+#ifdef USE_VECTOR_LINE_INTERSECTION
+
+ /* from isect_line_line_v2_point() */
+
+ double s10[2], s32[2];
+ double div;
+
+ sub_v2_v2v2_db(s10, a2, a1);
+ sub_v2_v2v2_db(s32, b2, b1);
+
+ div = cross_v2v2_db(s10, s32);
+ if (div != 0.0f) {
+ const double u = cross_v2v2_db(a2, a1);
+ const double v = cross_v2v2_db(b2, b1);
+
+ const double rx = ((s32[0] * u) - (s10[0] * v)) / div;
+ const double ry = ((s32[1] * u) - (s10[1] * v)) / div;
+ double rr;
+
+ if (fabs(a2[0] - a1[0]) > fabs(a2[1] - a1[1])) {
+ *aRatio = ratiod(a1[0], a2[0], rx);
+ if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) {
+ rr = ratiod(b1[0], b2[0], rx);
+ }
+ else {
+ rr = ratiod(b1[1], b2[1], ry);
+ }
+ if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) {
+ return 1;
+ }
+ return 0;
+ }
+
+ *aRatio = ratiod(a1[1], a2[1], ry);
+ if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) {
+ rr = ratiod(b1[0], b2[0], rx);
+ }
+ else {
+ rr = ratiod(b1[1], b2[1], ry);
+ }
+ if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) {
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+
+#else
+ double k1, k2;
+ double x;
+ double y;
+ double ratio;
+ double x_diff = (a2[0] - a1[0]);
+ double x_diff2 = (b2[0] - b1[0]);
+
+ if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff, 0)) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
+ *aRatio = 0;
+ return 0;
+ }
+ double r2 = ratiod(b1[0], b2[0], a1[0]);
+ x = interpd(b2[0], b1[0], r2);
+ y = interpd(b2[1], b1[1], r2);
+ *aRatio = ratio = ratiod(a1[1], a2[1], y);
+ }
+ else {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
+ ratio = ratiod(a1[0], a2[0], b1[0]);
+ x = interpd(a2[0], a1[0], ratio);
+ *aRatio = ratio;
+ }
+ else {
+ k1 = (a2[1] - a1[1]) / x_diff;
+ k2 = (b2[1] - b1[1]) / x_diff2;
+
+ if ((k1 == k2))
+ return 0;
+
+ x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
+
+ ratio = (x - a1[0]) / x_diff;
+
+ *aRatio = ratio;
+ }
+ }
+
+ if (LRT_DOUBLE_CLOSE_ENOUGH(b1[0], b2[0])) {
+ y = interpd(a2[1], a1[1], ratio);
+ if (y > MAX2(b1[1], b2[1]) || y < MIN2(b1[1], b2[1]))
+ return 0;
+ }
+ else if (ratio <= 0 || ratio > 1 || (b1[0] > b2[0] && x > b1[0]) ||
+ (b1[0] < b2[0] && x < b1[0]) || (b2[0] > b1[0] && x > b2[0]) ||
+ (b2[0] < b1[0] && x < b2[0]))
+ return 0;
+
+ return 1;
+#endif
+}
+
+struct Depsgraph;
+struct Scene;
+struct LineartRenderBuffer;
+struct LineartGpencilModifierData;
+
+void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd);
+
+void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
+void MOD_lineart_chain_connect(LineartRenderBuffer *rb, const bool do_geometry_space);
+void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
+void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
+
+int MOD_lineart_chain_count(const LineartLineChain *rlc);
+void MOD_lineart_chain_clear_picked_flag(struct LineartRenderBuffer *rb);
+
+int MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
+ struct LineartGpencilModifierData *lmd);
+
+struct Scene;
+
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
+ double x,
+ double y);
+
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
+
+struct bGPDlayer;
+struct bGPDframe;
+struct GpencilModifierData;
+
+void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
+ struct Depsgraph *depsgraph,
+ struct Object *ob,
+ struct bGPDlayer *gpl,
+ struct bGPDframe *gpf,
+ char source_type,
+ void *source_reference,
+ int level_start,
+ int level_end,
+ int mat_nr,
+ short line_types,
+ unsigned char transparency_flags,
+ unsigned char transparency_mask,
+ short thickness,
+ float opacity,
+ float pre_sample_length,
+ const char *source_vgname,
+ const char *vgname,
+ int modifier_flags);
+
+float MOD_lineart_chain_compute_length(LineartLineChain *rlc);
+
+struct wmOperatorType;
+
+void ED_operatortypes_lineart(void);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
new file mode 100644
index 00000000000..10a028d94cc
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -0,0 +1,987 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_customdata.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_lineart_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "MOD_lineart.h"
+
+#include "bmesh.h"
+
+#include "lineart_intern.h"
+
+#include <math.h>
+
+#define LRT_OTHER_RV(rl, rv) ((rv) == (rl)->l ? (rl)->r : ((rv) == (rl)->r ? (rl)->l : NULL))
+
+/* Get a connected line, only for lines who has the exact given vert, or (in the case of
+ * intersection lines) who has a vert that has the exact same position. */
+static LineartLine *lineart_line_get_connected(LineartBoundingArea *ba,
+ LineartVert *rv,
+ LineartVert **new_rv,
+ int match_flag)
+{
+ LISTBASE_FOREACH (LinkData *, lip, &ba->linked_lines) {
+ LineartLine *nrl = lip->data;
+
+ if ((!(nrl->flags & LRT_EDGE_FLAG_ALL_TYPE)) || (nrl->flags & LRT_EDGE_FLAG_CHAIN_PICKED)) {
+ continue;
+ }
+
+ if (match_flag && ((nrl->flags & LRT_EDGE_FLAG_ALL_TYPE) & match_flag) == 0) {
+ continue;
+ }
+
+ *new_rv = LRT_OTHER_RV(nrl, rv);
+ if (*new_rv) {
+ return nrl;
+ }
+
+ if (nrl->flags & LRT_EDGE_FLAG_INTERSECTION) {
+ if (rv->fbcoord[0] == nrl->l->fbcoord[0] && rv->fbcoord[1] == nrl->l->fbcoord[1]) {
+ *new_rv = LRT_OTHER_RV(nrl, nrl->l);
+ return nrl;
+ }
+ if (rv->fbcoord[0] == nrl->r->fbcoord[0] && rv->fbcoord[1] == nrl->r->fbcoord[1]) {
+ *new_rv = LRT_OTHER_RV(nrl, nrl->r);
+ return nrl;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static LineartLineChain *lineart_chain_create(LineartRenderBuffer *rb)
+{
+ LineartLineChain *rlc;
+ rlc = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLineChain));
+
+ BLI_addtail(&rb->chains, rlc);
+
+ return rlc;
+}
+
+static bool lineart_point_overlapping(LineartLineChainItem *rlci,
+ float x,
+ float y,
+ double threshold)
+{
+ if (!rlci) {
+ return false;
+ }
+ if (((rlci->pos[0] + threshold) >= x) && ((rlci->pos[0] - threshold) <= x) &&
+ ((rlci->pos[1] + threshold) >= y) && ((rlci->pos[1] - threshold) <= y)) {
+ return true;
+ }
+ return false;
+}
+
+static LineartLineChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
+ LineartLineChain *rlc,
+ float *fbcoord,
+ float *gpos,
+ float *normal,
+ char type,
+ int level,
+ unsigned char transparency_mask,
+ size_t index)
+{
+ LineartLineChainItem *rlci;
+
+ if (lineart_point_overlapping(rlc->chain.last, fbcoord[0], fbcoord[1], 1e-5)) {
+ /* Because the new chain point is overlapping, just replace the type and occlusion level of the
+ * current point. This makes it so that the line to the point after this one has the correct
+ * type and level. */
+ LineartLineChainItem *old_rlci = rlc->chain.last;
+ old_rlci->line_type = type;
+ old_rlci->occlusion = level;
+ old_rlci->transparency_mask = transparency_mask;
+ return old_rlci;
+ }
+
+ rlci = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLineChainItem));
+
+ copy_v2_v2(rlci->pos, fbcoord);
+ copy_v3_v3(rlci->gpos, gpos);
+ rlci->index = index;
+ copy_v3_v3(rlci->normal, normal);
+ rlci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE;
+ rlci->occlusion = level;
+ rlci->transparency_mask = transparency_mask;
+ BLI_addtail(&rlc->chain, rlci);
+
+ return rlci;
+}
+
+static LineartLineChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb,
+ LineartLineChain *rlc,
+ float *fbcoord,
+ float *gpos,
+ float *normal,
+ char type,
+ int level,
+ unsigned char transparency_mask,
+ size_t index)
+{
+ LineartLineChainItem *rlci;
+
+ if (lineart_point_overlapping(rlc->chain.first, fbcoord[0], fbcoord[1], 1e-5)) {
+ return rlc->chain.first;
+ }
+
+ rlci = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLineChainItem));
+
+ copy_v2_v2(rlci->pos, fbcoord);
+ copy_v3_v3(rlci->gpos, gpos);
+ rlci->index = index;
+ copy_v3_v3(rlci->normal, normal);
+ rlci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE;
+ rlci->occlusion = level;
+ rlci->transparency_mask = transparency_mask;
+ BLI_addhead(&rlc->chain, rlci);
+
+ return rlci;
+}
+
+void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
+{
+ LineartLineChain *rlc;
+ LineartLineChainItem *rlci;
+ LineartBoundingArea *ba;
+ LineartLineSegment *rls;
+ int last_occlusion;
+ unsigned char last_transparency;
+ /* Used when converting from double. */
+ float use_fbcoord[2];
+ float use_gpos[3];
+
+#define VERT_COORD_TO_FLOAT(a) \
+ copy_v2fl_v2db(use_fbcoord, (a)->fbcoord); \
+ copy_v3fl_v3db(use_gpos, (a)->gloc);
+
+#define POS_TO_FLOAT(lpos, gpos) \
+ copy_v2fl_v2db(use_fbcoord, lpos); \
+ copy_v3fl_v3db(use_gpos, gpos);
+
+ LRT_ITER_ALL_LINES_BEGIN
+ {
+ if ((!(rl->flags & LRT_EDGE_FLAG_ALL_TYPE)) || (rl->flags & LRT_EDGE_FLAG_CHAIN_PICKED)) {
+ LRT_ITER_ALL_LINES_NEXT
+ continue;
+ }
+
+ rl->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
+
+ rlc = lineart_chain_create(rb);
+
+ /* One chain can only have one object_ref,
+ * so we assign it based on the first segment we found. */
+ rlc->object_ref = rl->object_ref;
+
+ LineartLine *new_rl = rl;
+ LineartVert *new_rv;
+ float N[3] = {0};
+
+ if (rl->tl) {
+ N[0] += rl->tl->gn[0];
+ N[1] += rl->tl->gn[1];
+ N[2] += rl->tl->gn[2];
+ }
+ if (rl->tr) {
+ N[0] += rl->tr->gn[0];
+ N[1] += rl->tr->gn[1];
+ N[2] += rl->tr->gn[2];
+ }
+ if (rl->tl || rl->tr) {
+ normalize_v3(N);
+ }
+
+ /* Step 1: grow left. */
+ ba = MOD_lineart_get_bounding_area(rb, rl->l->fbcoord[0], rl->l->fbcoord[1]);
+ new_rv = rl->l;
+ rls = rl->segments.first;
+ VERT_COORD_TO_FLOAT(new_rv);
+ lineart_chain_prepend_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ rl->flags,
+ rls->occlusion,
+ rls->transparency_mask,
+ rl->l_obindex);
+ while (ba && (new_rl = lineart_line_get_connected(ba, new_rv, &new_rv, rl->flags))) {
+ new_rl->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
+
+ if (new_rl->tl || new_rl->tr) {
+ zero_v3(N);
+ if (new_rl->tl) {
+ N[0] += new_rl->tl->gn[0];
+ N[1] += new_rl->tl->gn[1];
+ N[2] += new_rl->tl->gn[2];
+ }
+ if (new_rl->tr) {
+ N[0] += new_rl->tr->gn[0];
+ N[1] += new_rl->tr->gn[1];
+ N[2] += new_rl->tr->gn[2];
+ }
+ normalize_v3(N);
+ }
+
+ if (new_rv == new_rl->l) {
+ for (rls = new_rl->segments.last; rls; rls = rls->prev) {
+ double gpos[3], lpos[3];
+ double *lfb = new_rl->l->fbcoord, *rfb = new_rl->r->fbcoord;
+ double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, global_at);
+ POS_TO_FLOAT(lpos, gpos)
+ lineart_chain_prepend_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ new_rl->flags,
+ rls->occlusion,
+ rls->transparency_mask,
+ new_rl->l_obindex);
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ }
+ }
+ else if (new_rv == new_rl->r) {
+ rls = new_rl->segments.first;
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ rls = rls->next;
+ for (; rls; rls = rls->next) {
+ double gpos[3], lpos[3];
+ double *lfb = new_rl->l->fbcoord, *rfb = new_rl->r->fbcoord;
+ double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, global_at);
+ POS_TO_FLOAT(lpos, gpos)
+ lineart_chain_prepend_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ new_rl->flags,
+ last_occlusion,
+ last_transparency,
+ new_rl->r_obindex);
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ }
+ VERT_COORD_TO_FLOAT(new_rl->r);
+ lineart_chain_prepend_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ new_rl->flags,
+ last_occlusion,
+ last_transparency,
+ new_rl->r_obindex);
+ }
+ ba = MOD_lineart_get_bounding_area(rb, new_rv->fbcoord[0], new_rv->fbcoord[1]);
+ }
+
+ /* Restore normal value. */
+ if (rl->tl || rl->tr) {
+ zero_v3(N);
+ if (rl->tl) {
+ N[0] += rl->tl->gn[0];
+ N[1] += rl->tl->gn[1];
+ N[2] += rl->tl->gn[2];
+ }
+ if (rl->tr) {
+ N[0] += rl->tr->gn[0];
+ N[1] += rl->tr->gn[1];
+ N[2] += rl->tr->gn[2];
+ }
+ normalize_v3(N);
+ }
+ /* Step 2: Adding all cuts from the given line, so we can continue connecting the right side
+ * of the line. */
+ rls = rl->segments.first;
+ last_occlusion = ((LineartLineSegment *)rls)->occlusion;
+ last_transparency = ((LineartLineSegment *)rls)->transparency_mask;
+ for (rls = rls->next; rls; rls = rls->next) {
+ double gpos[3], lpos[3];
+ double *lfb = rl->l->fbcoord, *rfb = rl->r->fbcoord;
+ double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
+ interp_v3_v3v3_db(lpos, rl->l->fbcoord, rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, rl->l->gloc, rl->r->gloc, global_at);
+ POS_TO_FLOAT(lpos, gpos)
+ lineart_chain_append_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ rl->flags,
+ rls->occlusion,
+ rls->transparency_mask,
+ rl->l_obindex);
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ }
+ VERT_COORD_TO_FLOAT(rl->r)
+ lineart_chain_append_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ rl->flags,
+ last_occlusion,
+ last_transparency,
+ rl->r_obindex);
+
+ /* Step 3: grow right. */
+ ba = MOD_lineart_get_bounding_area(rb, rl->r->fbcoord[0], rl->r->fbcoord[1]);
+ new_rv = rl->r;
+ while (ba && (new_rl = lineart_line_get_connected(ba, new_rv, &new_rv, rl->flags))) {
+ new_rl->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
+
+ if (new_rl->tl || new_rl->tr) {
+ zero_v3(N);
+ if (new_rl->tl) {
+ N[0] += new_rl->tl->gn[0];
+ N[1] += new_rl->tl->gn[1];
+ N[2] += new_rl->tl->gn[2];
+ }
+ if (new_rl->tr) {
+ N[0] += new_rl->tr->gn[0];
+ N[1] += new_rl->tr->gn[1];
+ N[2] += new_rl->tr->gn[2];
+ }
+ normalize_v3(N);
+ }
+
+ /* Fix leading vertex type. */
+ rlci = rlc->chain.last;
+ rlci->line_type = new_rl->flags & LRT_EDGE_FLAG_ALL_TYPE;
+
+ if (new_rv == new_rl->l) {
+ rls = new_rl->segments.last;
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ /* Fix leading vertex occlusion. */
+ rlci->occlusion = last_occlusion;
+ rlci->transparency_mask = last_transparency;
+ for (rls = new_rl->segments.last; rls; rls = rls->prev) {
+ double gpos[3], lpos[3];
+ double *lfb = new_rl->l->fbcoord, *rfb = new_rl->r->fbcoord;
+ double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, global_at);
+ last_occlusion = rls->prev ? rls->prev->occlusion : last_occlusion;
+ last_transparency = rls->prev ? rls->prev->transparency_mask : last_transparency;
+ POS_TO_FLOAT(lpos, gpos)
+ lineart_chain_append_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ new_rl->flags,
+ last_occlusion,
+ last_transparency,
+ new_rl->l_obindex);
+ }
+ }
+ else if (new_rv == new_rl->r) {
+ rls = new_rl->segments.first;
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ rlci->occlusion = last_occlusion;
+ rlci->transparency_mask = last_transparency;
+ rls = rls->next;
+ for (; rls; rls = rls->next) {
+ double gpos[3], lpos[3];
+ double *lfb = new_rl->l->fbcoord, *rfb = new_rl->r->fbcoord;
+ double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, global_at);
+ POS_TO_FLOAT(lpos, gpos)
+ lineart_chain_append_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ new_rl->flags,
+ rls->occlusion,
+ rls->transparency_mask,
+ new_rl->r_obindex);
+ last_occlusion = rls->occlusion;
+ last_transparency = rls->transparency_mask;
+ }
+ VERT_COORD_TO_FLOAT(new_rl->r)
+ lineart_chain_append_point(rb,
+ rlc,
+ use_fbcoord,
+ use_gpos,
+ N,
+ new_rl->flags,
+ last_occlusion,
+ last_transparency,
+ new_rl->r_obindex);
+ }
+ ba = MOD_lineart_get_bounding_area(rb, new_rv->fbcoord[0], new_rv->fbcoord[1]);
+ }
+ if (rb->fuzzy_everything) {
+ rlc->type = LRT_EDGE_FLAG_CONTOUR;
+ }
+ else {
+ rlc->type = (rl->flags & LRT_EDGE_FLAG_ALL_TYPE);
+ }
+ }
+ LRT_ITER_ALL_LINES_END
+}
+
+static LineartBoundingArea *lineart_bounding_area_get_rlci_recursive(LineartRenderBuffer *rb,
+ LineartBoundingArea *root,
+ LineartLineChainItem *rlci)
+{
+ if (root->child == NULL) {
+ return root;
+ }
+
+ LineartBoundingArea *ch = root->child;
+#define IN_BOUND(ba, rlci) \
+ ba.l <= rlci->pos[0] && ba.r >= rlci->pos[0] && ba.b <= rlci->pos[1] && ba.u >= rlci->pos[1]
+
+ if (IN_BOUND(ch[0], rlci)) {
+ return lineart_bounding_area_get_rlci_recursive(rb, &ch[0], rlci);
+ }
+ if (IN_BOUND(ch[1], rlci)) {
+ return lineart_bounding_area_get_rlci_recursive(rb, &ch[1], rlci);
+ }
+ if (IN_BOUND(ch[2], rlci)) {
+ return lineart_bounding_area_get_rlci_recursive(rb, &ch[2], rlci);
+ }
+ if (IN_BOUND(ch[3], rlci)) {
+ return lineart_bounding_area_get_rlci_recursive(rb, &ch[3], rlci);
+ }
+#undef IN_BOUND
+ return NULL;
+}
+
+static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuffer *rb,
+ LineartLineChainItem *rlci)
+{
+ if (!rlci) {
+ return NULL;
+ }
+ LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, rlci->pos[0], rlci->pos[1]);
+ if (root == NULL) {
+ return NULL;
+ }
+ return lineart_bounding_area_get_rlci_recursive(rb, root, rlci);
+}
+
+/* Here we will try to connect geometry space chains together in image space. However we can't
+ * chain two chains together if their end and start points lie on the border between two bounding
+ * areas, this happens either when 1) the geometry is way too dense, or 2) the chaining threshold
+ * is too big that it covers multiple small bounding areas. */
+static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
+ LineartBoundingArea *root,
+ LineartLineChain *rlc,
+ LineartLineChainItem *rlci)
+{
+ if (root->child == NULL) {
+ LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized(
+ &root->linked_chains, &rb->render_data_pool, rlc, sizeof(LineartChainRegisterEntry));
+
+ cre->rlci = rlci;
+
+ if (rlci == rlc->chain.first) {
+ cre->is_left = 1;
+ }
+ }
+ else {
+ LineartBoundingArea *ch = root->child;
+
+#define IN_BOUND(ba, rlci) \
+ ba.l <= rlci->pos[0] && ba.r >= rlci->pos[0] && ba.b <= rlci->pos[1] && ba.u >= rlci->pos[1]
+
+ if (IN_BOUND(ch[0], rlci)) {
+ lineart_bounding_area_link_point_recursive(rb, &ch[0], rlc, rlci);
+ }
+ else if (IN_BOUND(ch[1], rlci)) {
+ lineart_bounding_area_link_point_recursive(rb, &ch[1], rlc, rlci);
+ }
+ else if (IN_BOUND(ch[2], rlci)) {
+ lineart_bounding_area_link_point_recursive(rb, &ch[2], rlc, rlci);
+ }
+ else if (IN_BOUND(ch[3], rlci)) {
+ lineart_bounding_area_link_point_recursive(rb, &ch[3], rlc, rlci);
+ }
+
+#undef IN_BOUND
+ }
+}
+
+static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartLineChain *rlc)
+{
+ LineartLineChainItem *pl = rlc->chain.first;
+ LineartLineChainItem *pr = rlc->chain.last;
+ LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(rb, pl->pos[0], pl->pos[1]);
+ LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(rb, pr->pos[0], pr->pos[1]);
+
+ if (ba1) {
+ lineart_bounding_area_link_point_recursive(rb, ba1, rlc, pl);
+ }
+ if (ba2) {
+ lineart_bounding_area_link_point_recursive(rb, ba2, rlc, pr);
+ }
+}
+
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
+{
+ LineartLineChain *rlc, *new_rlc;
+ LineartLineChainItem *rlci, *next_rlci;
+ ListBase swap = {0};
+
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+
+ while ((rlc = BLI_pophead(&swap)) != NULL) {
+ rlc->next = rlc->prev = NULL;
+ BLI_addtail(&rb->chains, rlc);
+ LineartLineChainItem *first_rlci = (LineartLineChainItem *)rlc->chain.first;
+ int fixed_occ = first_rlci->occlusion;
+ unsigned char fixed_mask = first_rlci->transparency_mask;
+ rlc->level = fixed_occ;
+ rlc->transparency_mask = fixed_mask;
+ for (rlci = first_rlci->next; rlci; rlci = next_rlci) {
+ next_rlci = rlci->next;
+ if (rlci->occlusion != fixed_occ || rlci->transparency_mask != fixed_mask) {
+ if (next_rlci) {
+ if (lineart_point_overlapping(next_rlci, rlci->pos[0], rlci->pos[1], 1e-5)) {
+ continue;
+ }
+ }
+ else {
+ /* Set the same occlusion level for the end vertex, so when further connection is needed
+ * the backwards occlusion info is also correct. */
+ rlci->occlusion = fixed_occ;
+ rlci->transparency_mask = fixed_mask;
+ /* No need to split at the last point anyway. */
+ break;
+ }
+ new_rlc = lineart_chain_create(rb);
+ new_rlc->chain.first = rlci;
+ new_rlc->chain.last = rlc->chain.last;
+ rlc->chain.last = rlci->prev;
+ ((LineartLineChainItem *)rlc->chain.last)->next = 0;
+ rlci->prev = 0;
+
+ /* End the previous one. */
+ lineart_chain_append_point(rb,
+ rlc,
+ rlci->pos,
+ rlci->gpos,
+ rlci->normal,
+ rlci->line_type,
+ fixed_occ,
+ fixed_mask,
+ rlci->index);
+ new_rlc->object_ref = rlc->object_ref;
+ new_rlc->type = rlc->type;
+ rlc = new_rlc;
+ fixed_occ = rlci->occlusion;
+ fixed_mask = rlci->transparency_mask;
+ rlc->level = fixed_occ;
+ rlc->transparency_mask = fixed_mask;
+ }
+ }
+ }
+ LISTBASE_FOREACH (LineartLineChain *, irlc, &rb->chains) {
+ lineart_bounding_area_link_chain(rb, irlc);
+ }
+}
+
+/* Note: segment type (crease/material/contour...) is ambiguous after this. */
+static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
+ LineartLineChain *onto,
+ LineartLineChain *sub,
+ int reverse_1,
+ int reverse_2)
+{
+ LineartLineChainItem *rlci;
+ if (onto->type == LRT_EDGE_FLAG_INTERSECTION) {
+ if (sub->object_ref) {
+ onto->object_ref = sub->object_ref;
+ onto->type = LRT_EDGE_FLAG_CONTOUR;
+ }
+ }
+ else if (sub->type == LRT_EDGE_FLAG_INTERSECTION) {
+ if (onto->type != LRT_EDGE_FLAG_INTERSECTION) {
+ onto->type = LRT_EDGE_FLAG_CONTOUR;
+ }
+ }
+ if (!reverse_1) { /* L--R L-R. */
+ if (reverse_2) { /* L--R R-L. */
+ BLI_listbase_reverse(&sub->chain);
+ }
+ rlci = sub->chain.first;
+ if (lineart_point_overlapping(onto->chain.last, rlci->pos[0], rlci->pos[1], 1e-5)) {
+ BLI_pophead(&sub->chain);
+ if (sub->chain.first == NULL) {
+ return;
+ }
+ }
+ ((LineartLineChainItem *)onto->chain.last)->next = sub->chain.first;
+ ((LineartLineChainItem *)sub->chain.first)->prev = onto->chain.last;
+ onto->chain.last = sub->chain.last;
+ }
+ else { /* L-R L--R. */
+ if (!reverse_2) { /* R-L L--R. */
+ BLI_listbase_reverse(&sub->chain);
+ }
+ rlci = onto->chain.first;
+ if (lineart_point_overlapping(sub->chain.last, rlci->pos[0], rlci->pos[1], 1e-5)) {
+ BLI_pophead(&onto->chain);
+ if (onto->chain.first == NULL) {
+ return;
+ }
+ }
+ ((LineartLineChainItem *)sub->chain.last)->next = onto->chain.first;
+ ((LineartLineChainItem *)onto->chain.first)->prev = sub->chain.last;
+ onto->chain.first = sub->chain.first;
+ }
+}
+
+static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuffer *rb,
+ LineartBoundingArea *ba,
+ LineartLineChain *rlc,
+ LineartLineChainItem *rlci,
+ int occlusion,
+ unsigned char transparency_mask,
+ float dist,
+ int do_geometry_space,
+ float *result_new_len,
+ LineartBoundingArea *caller_ba)
+{
+
+ LineartChainRegisterEntry *closest_cre = NULL;
+
+ /* Keep using for loop because cre could be removed from the iteration before getting to the
+ * next one. */
+ LISTBASE_FOREACH_MUTABLE (LineartChainRegisterEntry *, cre, &ba->linked_chains) {
+ if (cre->rlc->object_ref != rlc->object_ref) {
+ if (!rb->fuzzy_everything) {
+ if (rb->fuzzy_intersections) {
+ /* If none of those are intersection lines... */
+ if ((!(cre->rlc->type & LRT_EDGE_FLAG_INTERSECTION)) &&
+ (!(rlc->type & LRT_EDGE_FLAG_INTERSECTION))) {
+ continue; /* We don't want to chain along different objects at the moment. */
+ }
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ if (cre->rlc->picked || cre->picked) {
+ continue;
+ }
+ if (cre->rlc == rlc || (!cre->rlc->chain.first) || (cre->rlc->level != occlusion) ||
+ (cre->rlc->transparency_mask != transparency_mask)) {
+ continue;
+ }
+ if (!rb->fuzzy_everything) {
+ if (cre->rlc->type != rlc->type) {
+ if (rb->fuzzy_intersections) {
+ if (!(cre->rlc->type == LRT_EDGE_FLAG_INTERSECTION ||
+ rlc->type == LRT_EDGE_FLAG_INTERSECTION)) {
+ continue; /* Fuzzy intersetions but no intersection line found. */
+ }
+ }
+ else { /* Line type different but no fuzzy. */
+ continue;
+ }
+ }
+ }
+
+ float new_len = do_geometry_space ? len_v3v3(cre->rlci->gpos, rlci->gpos) :
+ len_v2v2(cre->rlci->pos, rlci->pos);
+ if (new_len < dist) {
+ closest_cre = cre;
+ dist = new_len;
+ if (result_new_len) {
+ (*result_new_len) = new_len;
+ }
+ }
+ }
+
+ /* We want a closer point anyway. So using modified dist is fine. */
+ float adjacent_new_len = dist;
+ LineartChainRegisterEntry *adjacent_closest;
+
+#define LRT_TEST_ADJACENT_AREAS(dist_to, list) \
+ if (dist_to < dist && dist_to > 0) { \
+ LISTBASE_FOREACH (LinkData *, ld, list) { \
+ LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \
+ adjacent_closest = lineart_chain_get_closest_cre(rb, \
+ sba, \
+ rlc, \
+ rlci, \
+ occlusion, \
+ transparency_mask, \
+ dist, \
+ do_geometry_space, \
+ &adjacent_new_len, \
+ ba); \
+ if (adjacent_new_len < dist) { \
+ dist = adjacent_new_len; \
+ closest_cre = adjacent_closest; \
+ } \
+ } \
+ }
+ if (!do_geometry_space && !caller_ba) {
+ LRT_TEST_ADJACENT_AREAS(rlci->pos[0] - ba->l, &ba->lp);
+ LRT_TEST_ADJACENT_AREAS(ba->r - rlci->pos[0], &ba->rp);
+ LRT_TEST_ADJACENT_AREAS(ba->u - rlci->pos[1], &ba->up);
+ LRT_TEST_ADJACENT_AREAS(rlci->pos[1] - ba->b, &ba->bp);
+ }
+ if (result_new_len) {
+ (*result_new_len) = dist;
+ }
+ return closest_cre;
+}
+
+/* This function only connects two different chains. It will not do any clean up or smart chaining.
+ * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
+ * implemented yet. */
+void MOD_lineart_chain_connect(LineartRenderBuffer *rb, const bool do_geometry_space)
+{
+ LineartLineChain *rlc;
+ LineartLineChainItem *rlci_l, *rlci_r;
+ LineartBoundingArea *ba_l, *ba_r;
+ LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
+ float dist = do_geometry_space ? rb->chaining_geometry_threshold : rb->chaining_image_threshold;
+ float dist_l, dist_r;
+ int occlusion, reverse_main;
+ unsigned char transparency_mask;
+ ListBase swap = {0};
+
+ if ((!do_geometry_space && rb->chaining_image_threshold < 0.0001) ||
+ (do_geometry_space && rb->chaining_geometry_threshold < 0.0001)) {
+ return;
+ }
+
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+
+ while ((rlc = BLI_pophead(&swap)) != NULL) {
+ rlc->next = rlc->prev = NULL;
+ if (rlc->picked) {
+ continue;
+ }
+ BLI_addtail(&rb->chains, rlc);
+
+ occlusion = rlc->level;
+ transparency_mask = rlc->transparency_mask;
+
+ rlci_l = rlc->chain.first;
+ rlci_r = rlc->chain.last;
+ while ((ba_l = lineart_bounding_area_get_end_point(rb, rlci_l)) &&
+ (ba_r = lineart_bounding_area_get_end_point(rb, rlci_r))) {
+ closest_cre_l = lineart_chain_get_closest_cre(rb,
+ ba_l,
+ rlc,
+ rlci_l,
+ occlusion,
+ transparency_mask,
+ dist,
+ do_geometry_space,
+ &dist_l,
+ NULL);
+ closest_cre_r = lineart_chain_get_closest_cre(rb,
+ ba_r,
+ rlc,
+ rlci_r,
+ occlusion,
+ transparency_mask,
+ dist,
+ do_geometry_space,
+ &dist_r,
+ NULL);
+ if (closest_cre_l && closest_cre_r) {
+ if (dist_l < dist_r) {
+ closest_cre = closest_cre_l;
+ reverse_main = 1;
+ }
+ else {
+ closest_cre = closest_cre_r;
+ reverse_main = 0;
+ }
+ }
+ else if (closest_cre_l) {
+ closest_cre = closest_cre_l;
+ reverse_main = 1;
+ }
+ else if (closest_cre_r) {
+ closest_cre = closest_cre_r;
+ BLI_remlink(&ba_r->linked_chains, closest_cre_r);
+ reverse_main = 0;
+ }
+ else {
+ break;
+ }
+ closest_cre->picked = 1;
+ closest_cre->rlc->picked = 1;
+ if (closest_cre->is_left) {
+ lineart_chain_connect(rb, rlc, closest_cre->rlc, reverse_main, 0);
+ }
+ else {
+ lineart_chain_connect(rb, rlc, closest_cre->rlc, reverse_main, 1);
+ }
+ BLI_remlink(&swap, closest_cre->rlc);
+ rlci_l = rlc->chain.first;
+ rlci_r = rlc->chain.last;
+ }
+ rlc->picked = 1;
+ }
+}
+
+/* Length is in image space. */
+float MOD_lineart_chain_compute_length(LineartLineChain *rlc)
+{
+ LineartLineChainItem *rlci;
+ float offset_accum = 0;
+ float dist;
+ float last_point[2];
+
+ rlci = rlc->chain.first;
+ copy_v2_v2(last_point, rlci->pos);
+ for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
+ dist = len_v2v2(rlci->pos, last_point);
+ offset_accum += dist;
+ copy_v2_v2(last_point, rlci->pos);
+ }
+ return offset_accum;
+}
+
+void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
+{
+ LineartLineChain *rlc, *next_rlc;
+ for (rlc = rb->chains.first; rlc; rlc = next_rlc) {
+ next_rlc = rlc->next;
+ if (MOD_lineart_chain_compute_length(rlc) < threshold) {
+ BLI_remlink(&rb->chains, rlc);
+ }
+ }
+}
+
+int MOD_lineart_chain_count(const LineartLineChain *rlc)
+{
+ int count = 0;
+ LISTBASE_FOREACH (LineartLineChainItem *, rlci, &rlc->chain) {
+ count++;
+ }
+ return count;
+}
+
+void MOD_lineart_chain_clear_picked_flag(LineartRenderBuffer *rb)
+{
+ if (rb == NULL) {
+ return;
+ }
+ LISTBASE_FOREACH (LineartLineChain *, rlc, &rb->chains) {
+ rlc->picked = 0;
+ }
+}
+
+/* This should always be the last stage!, see the end of
+ * MOD_lineart_chain_split_for_fixed_occlusion().*/
+void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
+{
+ LineartLineChain *rlc, *new_rlc;
+ LineartLineChainItem *rlci, *next_rlci, *prev_rlci;
+ ListBase swap = {0};
+
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+
+ while ((rlc = BLI_pophead(&swap)) != NULL) {
+ rlc->next = rlc->prev = NULL;
+ BLI_addtail(&rb->chains, rlc);
+ LineartLineChainItem *first_rlci = (LineartLineChainItem *)rlc->chain.first;
+ for (rlci = first_rlci->next; rlci; rlci = next_rlci) {
+ next_rlci = rlci->next;
+ prev_rlci = rlci->prev;
+ float angle = M_PI;
+ if (next_rlci && prev_rlci) {
+ angle = angle_v2v2v2(prev_rlci->pos, rlci->pos, next_rlci->pos);
+ }
+ else {
+ break; /* No need to split at the last point anyway.*/
+ }
+ if (angle < angle_threshold_rad) {
+ new_rlc = lineart_chain_create(rb);
+ new_rlc->chain.first = rlci;
+ new_rlc->chain.last = rlc->chain.last;
+ rlc->chain.last = rlci->prev;
+ ((LineartLineChainItem *)rlc->chain.last)->next = 0;
+ rlci->prev = 0;
+
+ /* End the previous one. */
+ lineart_chain_append_point(rb,
+ rlc,
+ rlci->pos,
+ rlci->gpos,
+ rlci->normal,
+ rlci->line_type,
+ rlc->level,
+ rlci->transparency_mask,
+ rlci->index);
+ new_rlc->object_ref = rlc->object_ref;
+ new_rlc->type = rlc->type;
+ new_rlc->level = rlc->level;
+ new_rlc->transparency_mask = rlc->transparency_mask;
+ rlc = new_rlc;
+ }
+ }
+ }
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
new file mode 100644
index 00000000000..ca65fc9bd57
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -0,0 +1,3929 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/* \file
+ * \ingroup editors
+ */
+
+#include "MOD_lineart.h"
+
+#include "BLI_alloca.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_callbacks.h"
+#include "BKE_camera.h"
+#include "BKE_collection.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_text.h"
+#include "DEG_depsgraph_query.h"
+#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lineart_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_text_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "BLI_math.h"
+#include "BLI_string_utils.h"
+
+#include "bmesh.h"
+#include "bmesh_class.h"
+#include "bmesh_tools.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "lineart_intern.h"
+
+static LineartBoundingArea *lineart_line_first_bounding_area(LineartRenderBuffer *rb,
+ LineartLine *rl);
+
+static void lineart_bounding_area_link_line(LineartRenderBuffer *rb,
+ LineartBoundingArea *root_ba,
+ LineartLine *rl);
+
+static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *This,
+ LineartLine *rl,
+ double x,
+ double y,
+ double k,
+ int positive_x,
+ int positive_y,
+ double *next_x,
+ double *next_y);
+
+static bool lineart_get_line_bounding_areas(LineartRenderBuffer *rb,
+ LineartLine *rl,
+ int *rowbegin,
+ int *rowend,
+ int *colbegin,
+ int *colend);
+
+static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
+ LineartBoundingArea *root_ba,
+ LineartTriangle *rt,
+ double *LRUB,
+ int recursive,
+ int recursive_level,
+ bool do_intersection);
+
+static bool lineart_triangle_line_image_space_occlusion(SpinLock *spl,
+ const LineartTriangle *rt,
+ const LineartLine *rl,
+ const double *override_camera_loc,
+ const bool override_cam_is_persp,
+ const bool allow_overlapping_edges,
+ const double vp[4][4],
+ const double *camera_dir,
+ const float cam_shift_x,
+ const float cam_shift_y,
+ double *from,
+ double *to);
+
+static void lineart_add_line_to_list(LineartRenderBuffer *rb, LineartLine *rl);
+
+static void lineart_line_discard_segment(LineartRenderBuffer *rb, LineartLineSegment *rls)
+{
+ BLI_spin_lock(&rb->lock_cuts);
+
+ memset(rls, 0, sizeof(LineartLineSegment));
+
+ /* Storing the node for potentially reuse the memory for new segment data. Line Art data is not
+ * freed after all calulations are done. */
+ BLI_addtail(&rb->wasted_cuts, rls);
+
+ BLI_spin_unlock(&rb->lock_cuts);
+}
+
+static LineartLineSegment *lineart_line_give_segment(LineartRenderBuffer *rb)
+{
+ BLI_spin_lock(&rb->lock_cuts);
+
+ /* See if there is any already allocated memory we can reuse. */
+ if (rb->wasted_cuts.first) {
+ LineartLineSegment *rls = (LineartLineSegment *)BLI_pophead(&rb->wasted_cuts);
+ BLI_spin_unlock(&rb->lock_cuts);
+ memset(rls, 0, sizeof(LineartLineSegment));
+ return rls;
+ }
+ BLI_spin_unlock(&rb->lock_cuts);
+
+ /* Otherwise allocate some new memory. */
+ return (LineartLineSegment *)lineart_mem_aquire_thread(&rb->render_data_pool,
+ sizeof(LineartLineSegment));
+}
+
+/* Cuts the line in image space and mark occlusion level for each segment. */
+static void lineart_line_cut(LineartRenderBuffer *rb,
+ LineartLine *rl,
+ double start,
+ double end,
+ unsigned char transparency_mask)
+{
+ LineartLineSegment *rls, *irls, *next_rls, *prev_rls;
+ LineartLineSegment *cut_start_before = 0, *cut_end_before = 0;
+ LineartLineSegment *ns = 0, *ns2 = 0;
+ int untouched = 0;
+
+ /* If for some reason the occlusion function may give a result that has zero length, or reversed
+ * in direction, or NAN, we take care of them here. */
+ if (LRT_DOUBLE_CLOSE_ENOUGH(start, end)) {
+ return;
+ }
+ if (LRT_DOUBLE_CLOSE_ENOUGH(start, 1) || LRT_DOUBLE_CLOSE_ENOUGH(end, 0)) {
+ return;
+ }
+ if (UNLIKELY(start != start)) {
+ start = 0;
+ }
+ if (UNLIKELY(end != end)) {
+ end = 0;
+ }
+
+ if (start > end) {
+ double t = start;
+ start = end;
+ end = t;
+ }
+
+ /* Begin looking for starting position of the segment. */
+ /* Not using a list iteration macro because of it more clear when using for loops to iterate
+ * through the segments. */
+ for (rls = rl->segments.first; rls; rls = rls->next) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(rls->at, start)) {
+ cut_start_before = rls;
+ ns = cut_start_before;
+ break;
+ }
+ if (rls->next == NULL) {
+ break;
+ }
+ irls = rls->next;
+ if (irls->at > start + 1e-09 && start > rls->at) {
+ cut_start_before = irls;
+ ns = lineart_line_give_segment(rb);
+ break;
+ }
+ }
+ if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ untouched = 1;
+ }
+ for (rls = cut_start_before; rls; rls = rls->next) {
+ /* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle
+ * strip). */
+ if (LRT_DOUBLE_CLOSE_ENOUGH(rls->at, end)) {
+ cut_end_before = rls;
+ ns2 = cut_end_before;
+ break;
+ }
+ /* This check is to prevent rls->at == 1.0 (where we don't need to cut because we are at the
+ * end point). */
+ if (!rls->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ cut_end_before = rls;
+ ns2 = cut_end_before;
+ untouched = 1;
+ break;
+ }
+ /* When an actual cut is needed in the line. */
+ if (rls->at > end) {
+ cut_end_before = rls;
+ ns2 = lineart_line_give_segment(rb);
+ break;
+ }
+ }
+
+ /* When we still can't find any existing cut in the line, we allocate new ones. */
+ if (ns == NULL) {
+ ns = lineart_line_give_segment(rb);
+ }
+ if (ns2 == NULL) {
+ if (untouched) {
+ ns2 = ns;
+ cut_end_before = ns2;
+ }
+ else {
+ ns2 = lineart_line_give_segment(rb);
+ }
+ }
+
+ if (cut_start_before) {
+ if (cut_start_before != ns) {
+ /* Insert cutting points for when a new cut is needed. */
+ irls = cut_start_before->prev ? cut_start_before->prev : NULL;
+ ns->occlusion = irls ? irls->occlusion : 0;
+ ns->transparency_mask = irls->transparency_mask;
+ BLI_insertlinkbefore(&rl->segments, (void *)cut_start_before, (void *)ns);
+ }
+ /* Otherwise we already found a existing cutting point, no need to insert a new one. */
+ }
+ else {
+ /* We have yet to reach a existing cutting point even after we searched the whole line, so we
+ * append the new cut to the end. */
+ irls = rl->segments.last;
+ ns->occlusion = irls->occlusion;
+ ns->transparency_mask = irls->transparency_mask;
+ BLI_addtail(&rl->segments, ns);
+ }
+ if (cut_end_before) {
+ /* The same manipulation as on "cut_start_before". */
+ if (cut_end_before != ns2) {
+ irls = cut_end_before->prev ? cut_end_before->prev : NULL;
+ ns2->occlusion = irls ? irls->occlusion : 0;
+ ns2->transparency_mask = irls ? irls->transparency_mask : 0;
+ BLI_insertlinkbefore(&rl->segments, (void *)cut_end_before, (void *)ns2);
+ }
+ }
+ else {
+ irls = rl->segments.last;
+ ns2->occlusion = irls->occlusion;
+ ns2->transparency_mask = irls->transparency_mask;
+ BLI_addtail(&rl->segments, ns2);
+ }
+
+ /* If we touched the cut list, we assign the new cut position based on new cut position, this way
+ * we accomomdate precision lost due to multiple cut inserts. */
+ ns->at = start;
+ if (!untouched) {
+ ns2->at = end;
+ }
+ else {
+ /* For the convenience of the loop below. */
+ ns2 = ns2->next;
+ }
+
+ /* Register 1 level of occlusion for all touched segments. */
+ for (rls = ns; rls && rls != ns2; rls = rls->next) {
+ rls->occlusion++;
+ rls->transparency_mask |= transparency_mask;
+ }
+
+ /* Reduce adjacent cutting points of the same level, which saves memory. */
+ char min_occ = 127;
+ prev_rls = NULL;
+ for (rls = rl->segments.first; rls; rls = next_rls) {
+ next_rls = rls->next;
+
+ if (prev_rls && prev_rls->occlusion == rls->occlusion &&
+ prev_rls->transparency_mask == rls->transparency_mask) {
+ BLI_remlink(&rl->segments, rls);
+ /* This puts the node back to the render buffer, if more cut happens, these unused nodes get
+ * picked first. */
+ lineart_line_discard_segment(rb, rls);
+ continue;
+ }
+
+ min_occ = MIN2(min_occ, rls->occlusion);
+
+ prev_rls = rls;
+ }
+ rl->min_occ = min_occ;
+}
+
+/* To see if given line is connected to an adjacent intersection line. */
+BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartLine *rl, LineartTriangle *rt)
+{
+ LineartVertIntersection *l = (void *)rl->l;
+ LineartVertIntersection *r = (void *)rl->r;
+ return ((l->base.flag && l->intersecting_with == (void *)rt) ||
+ (r->base.flag && r->intersecting_with == (void *)rt));
+}
+
+static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartLine *rl, int thread_id)
+{
+ double x = rl->l->fbcoord[0], y = rl->l->fbcoord[1];
+ LineartBoundingArea *ba = lineart_line_first_bounding_area(rb, rl);
+ LineartBoundingArea *nba = ba;
+ LineartTriangleThread *rt;
+
+ /* These values are used for marching along the line. */
+ double l, r;
+ double k = (rl->r->fbcoord[1] - rl->l->fbcoord[1]) /
+ (rl->r->fbcoord[0] - rl->l->fbcoord[0] + 1e-30);
+ int positive_x = (rl->r->fbcoord[0] - rl->l->fbcoord[0]) > 0 ?
+ 1 :
+ (rl->r->fbcoord[0] == rl->l->fbcoord[0] ? 0 : -1);
+ int positive_y = (rl->r->fbcoord[1] - rl->l->fbcoord[1]) > 0 ?
+ 1 :
+ (rl->r->fbcoord[1] == rl->l->fbcoord[1] ? 0 : -1);
+
+ while (nba) {
+
+ LISTBASE_FOREACH (LinkData *, lip, &nba->linked_triangles) {
+ rt = lip->data;
+ /* If we are already testing the line in this thread, then don't do it. */
+ if (rt->testing[thread_id] == rl || (rt->base.flags & LRT_TRIANGLE_INTERSECTION_ONLY) ||
+ lineart_occlusion_is_adjacent_intersection(rl, (LineartTriangle *)rt)) {
+ continue;
+ }
+ rt->testing[thread_id] = rl;
+ if (lineart_triangle_line_image_space_occlusion(&rb->lock_task,
+ (void *)rt,
+ rl,
+ rb->camera_pos,
+ rb->cam_is_persp,
+ rb->allow_overlapping_edges,
+ rb->view_projection,
+ rb->view_vector,
+ rb->shift_x,
+ rb->shift_y,
+ &l,
+ &r)) {
+ lineart_line_cut(rb, rl, l, r, rt->base.transparency_mask);
+ if (rl->min_occ > rb->max_occlusion_level) {
+ /* No need to caluclate any longer on this line because no level more than set value is
+ * going to show up in the rendered result. */
+ return;
+ }
+ }
+ }
+ /* Marching along rl->l to rl->r, searching each possible bounding areas it may touch. */
+ nba = lineart_bounding_area_next(nba, rl, x, y, k, positive_x, positive_y, &x, &y);
+ }
+}
+
+static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRenderTaskInfo *rti)
+{
+ LineartLine *data;
+ int i;
+ int res = 0;
+
+ BLI_spin_lock(&rb->lock_task);
+
+#define LRT_ASSIGN_OCCLUSION_TASK(name) \
+ if (rb->name##_managed) { \
+ data = rb->name##_managed; \
+ rti->name = (void *)data; \
+ for (i = 0; i < LRT_THREAD_LINE_COUNT && data; i++) { \
+ data = data->next; \
+ } \
+ rti->name##_end = data; \
+ rb->name##_managed = data; \
+ res = 1; \
+ } \
+ else { \
+ rti->name = NULL; \
+ }
+
+ LRT_ASSIGN_OCCLUSION_TASK(contour);
+ LRT_ASSIGN_OCCLUSION_TASK(intersection);
+ LRT_ASSIGN_OCCLUSION_TASK(crease);
+ LRT_ASSIGN_OCCLUSION_TASK(material);
+ LRT_ASSIGN_OCCLUSION_TASK(edge_mark);
+
+#undef LRT_ASSIGN_OCCLUSION_TASK
+
+ BLI_spin_unlock(&rb->lock_task);
+
+ return res;
+}
+
+static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti)
+{
+ LineartRenderBuffer *rb = rti->rb;
+ LineartLine *lip;
+
+ while (lineart_occlusion_make_task_info(rb, rti)) {
+
+ for (lip = (void *)rti->contour; lip && lip != rti->contour_end; lip = lip->next) {
+ lineart_occlusion_single_line(rb, lip, rti->thread_id);
+ }
+
+ for (lip = (void *)rti->crease; lip && lip != rti->crease_end; lip = lip->next) {
+ lineart_occlusion_single_line(rb, lip, rti->thread_id);
+ }
+
+ for (lip = (void *)rti->intersection; lip && lip != rti->intersection_end; lip = lip->next) {
+ lineart_occlusion_single_line(rb, lip, rti->thread_id);
+ }
+
+ for (lip = (void *)rti->material; lip && lip != rti->material_end; lip = lip->next) {
+ lineart_occlusion_single_line(rb, lip, rti->thread_id);
+ }
+
+ for (lip = (void *)rti->edge_mark; lip && lip != rti->edge_mark_end; lip = lip->next) {
+ lineart_occlusion_single_line(rb, lip, rti->thread_id);
+ }
+ }
+}
+
+/* All internal functions starting with lineart_main_ is called inside
+ * MOD_lineart_compute_feature_lines function.
+ * This function handles all occlusion calculation. */
+static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
+{
+ int thread_count = rb->thread_count;
+ LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count,
+ "Task Pool");
+ int i;
+
+ rb->contour_managed = rb->contours;
+ rb->crease_managed = rb->crease_lines;
+ rb->intersection_managed = rb->intersection_lines;
+ rb->material_managed = rb->material_lines;
+ rb->edge_mark_managed = rb->edge_marks;
+
+ TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
+
+ for (i = 0; i < thread_count; i++) {
+ rti[i].thread_id = i;
+ rti[i].rb = rb;
+ BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, NULL);
+ }
+ BLI_task_pool_work_and_wait(tp);
+ BLI_task_pool_free(tp);
+
+ MEM_freeN(rti);
+}
+
+/* Test if v lies with in the triangle formed by v0, v1, and v2. Returns false when v is exactly on
+ * the edge.
+ * For v to be inside the triangle, it needs to be at the same side of v0->v1, v1->v2, and
+ * v2->v0, where the "side" is determined by checking the sign of cross(v1-v0, v1-v) and so on.
+ */
+static bool lineart_point_inside_triangle(const double v[2],
+ const double v0[2],
+ const double v1[2],
+ const double v2[2])
+{
+ double cl, c;
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ c = cl;
+
+ cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
+ if (c * cl <= 0) {
+ return false;
+ }
+
+ c = cl;
+
+ cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
+ if (c * cl <= 0) {
+ return false;
+ }
+
+ c = cl;
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ if (c * cl <= 0) {
+ return false;
+ }
+
+ return true;
+}
+
+static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2])
+{
+ /* c1!=c2 by default. */
+ double c1 = 1, c2 = 0;
+ double l0[2], l1[2];
+
+ sub_v2_v2v2_db(l0, v, v0);
+ sub_v2_v2v2_db(l1, v, v1);
+
+ if (v1[0] == v0[0] && v1[1] == v0[1]) {
+ return 0;
+ }
+
+ if (v1[0] - v0[0]) {
+ c1 = ratiod(v0[0], v1[0], v[0]);
+ }
+ else if (v[0] == v1[0]) {
+ c2 = ratiod(v0[1], v1[1], v[1]);
+ return (c2 >= 0 && c2 <= 1);
+ }
+
+ if (v1[1] - v0[1]) {
+ c2 = ratiod(v0[1], v1[1], v[1]);
+ }
+ else if (v[1] == v1[1]) {
+ c1 = ratiod(v0[0], v1[0], v[0]);
+ return (c1 >= 0 && c1 <= 1);
+ }
+
+ if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Same algorithm as lineart_point_inside_triangle(), but returns differently:
+ * 0-outside 1-on the edge 2-inside. */
+static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[2], double v2[2])
+{
+ double cl, c;
+ double r;
+ if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) ||
+ lineart_point_on_line_segment(v, v2, v0)) {
+ return 1;
+ }
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ c = cl;
+
+ cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
+ if ((r = c * cl) < 0) {
+ return 0;
+ }
+
+ c = cl;
+
+ cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
+ if ((r = c * cl) < 0) {
+ return 0;
+ }
+
+ c = cl;
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ if ((r = c * cl) < 0) {
+ return 0;
+ }
+
+ if (r == 0) {
+ return 1;
+ }
+
+ return 2;
+}
+
+/* Similar with lineart_point_inside_triangle, but in 3d.
+ * Returns false when not co-plannar. */
+static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1[3], double v2[3])
+{
+ double l[3], r[3];
+ double N1[3], N2[3];
+ double d;
+
+ sub_v3_v3v3_db(l, v1, v0);
+ sub_v3_v3v3_db(r, v, v1);
+ cross_v3_v3v3_db(N1, l, r);
+
+ sub_v3_v3v3_db(l, v2, v1);
+ sub_v3_v3v3_db(r, v, v2);
+ cross_v3_v3v3_db(N2, l, r);
+
+ if ((d = dot_v3v3_db(N1, N2)) < 0) {
+ return false;
+ }
+
+ sub_v3_v3v3_db(l, v0, v2);
+ sub_v3_v3v3_db(r, v, v0);
+ cross_v3_v3v3_db(N1, l, r);
+
+ if ((d = dot_v3v3_db(N1, N2)) < 0) {
+ return false;
+ }
+
+ sub_v3_v3v3_db(l, v1, v0);
+ sub_v3_v3v3_db(r, v, v1);
+ cross_v3_v3v3_db(N2, l, r);
+
+ if ((d = dot_v3v3_db(N1, N2)) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/* The following lineart_memory_get_XXX_space functions are for allocating new memory for some
+ * modified geometries in the culling stage. */
+static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBuffer *rb)
+{
+ LineartElementLinkNode *reln;
+
+ /* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles
+ * are relatively small. */
+ LineartTriangle *render_triangles = lineart_mem_aquire(&rb->render_data_pool,
+ 64 * rb->triangle_size);
+
+ reln = lineart_list_append_pointer_pool_sized(&rb->triangle_buffer_pointers,
+ &rb->render_data_pool,
+ render_triangles,
+ sizeof(LineartElementLinkNode));
+ reln->element_count = 64;
+ reln->flags |= LRT_ELEMENT_IS_ADDITIONAL;
+
+ return reln;
+}
+
+static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer *rb)
+{
+ LineartElementLinkNode *reln;
+
+ LineartVert *render_vertices = lineart_mem_aquire(&rb->render_data_pool,
+ sizeof(LineartVert) * 64);
+
+ reln = lineart_list_append_pointer_pool_sized(&rb->vertex_buffer_pointers,
+ &rb->render_data_pool,
+ render_vertices,
+ sizeof(LineartElementLinkNode));
+ reln->element_count = 64;
+ reln->flags |= LRT_ELEMENT_IS_ADDITIONAL;
+
+ return reln;
+}
+
+static LineartElementLinkNode *lineart_memory_get_line_space(LineartRenderBuffer *rb)
+{
+ LineartElementLinkNode *reln;
+
+ LineartLine *render_lines = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLine) * 64);
+
+ reln = lineart_list_append_pointer_pool_sized(&rb->line_buffer_pointers,
+ &rb->render_data_pool,
+ render_lines,
+ sizeof(LineartElementLinkNode));
+ reln->element_count = 64;
+ reln->crease_threshold = rb->crease_threshold;
+ reln->flags |= LRT_ELEMENT_IS_ADDITIONAL;
+
+ return reln;
+}
+
+static void lineart_triangle_post(LineartTriangle *rt, LineartTriangle *orig)
+{
+ /* Just re-assign normal and set cull flag. */
+ copy_v3_v3_db(rt->gn, orig->gn);
+ rt->flags = LRT_CULL_GENERATED;
+}
+
+static void lineart_triangle_set_cull_flag(LineartTriangle *rt, unsigned char flag)
+{
+ unsigned char intersection_only = (rt->flags & LRT_TRIANGLE_INTERSECTION_ONLY);
+ rt->flags = flag;
+ rt->flags |= intersection_only;
+}
+
+static bool lineart_line_match(LineartTriangle *rt, LineartLine *rl, int v1, int v2)
+{
+ return ((rt->v[v1] == rl->l && rt->v[v2] == rl->r) ||
+ (rt->v[v2] == rl->l && rt->v[v1] == rl->r));
+}
+
+/* Does near-plane cut on 1 triangle only. When cutting with far-plane, the camera vectors gets
+ * reversed by the caller so don't need to implement one in a different direction. */
+static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
+ LineartTriangle *rt,
+ int in0,
+ int in1,
+ int in2,
+ double *cam_pos,
+ double *view_dir,
+ bool allow_boundaries,
+ double (*vp)[4],
+ Object *ob,
+ int *r_v_count,
+ int *r_l_count,
+ int *r_t_count,
+ LineartElementLinkNode *veln,
+ LineartElementLinkNode *leln,
+ LineartElementLinkNode *teln)
+{
+ double vv1[3], vv2[3], dot1, dot2;
+ double a;
+ int v_count = *r_v_count;
+ int l_count = *r_l_count;
+ int t_count = *r_t_count;
+ int l_obi, r_obi;
+ char new_flag = 0;
+
+ LineartLine *new_rl, *rl, *old_rl;
+ LineartLineSegment *rls;
+ LineartTriangleAdjacent *rta;
+
+ if (rt->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) {
+ return;
+ }
+
+ /* See definition of rt->intersecting_verts and the usage in
+ * lineart_geometry_object_load() for details. */
+ rta = (void *)rt->intersecting_verts;
+
+ LineartVert *rv = &((LineartVert *)veln->pointer)[v_count];
+ LineartTriangle *rt1 = (void *)(((unsigned char *)teln->pointer) + rb->triangle_size * t_count);
+ LineartTriangle *rt2 = (void *)(((unsigned char *)teln->pointer) +
+ rb->triangle_size * (t_count + 1));
+
+ new_rl = &((LineartLine *)leln->pointer)[l_count];
+ /* Init rl to the last rl entry. */
+ rl = new_rl;
+
+#define INCREASE_RL \
+ l_count++; \
+ l_obi = rl->l_obindex; \
+ r_obi = rl->r_obindex; \
+ new_rl = &((LineartLine *)leln->pointer)[l_count]; \
+ rl = new_rl; \
+ rl->l_obindex = l_obi; \
+ rl->r_obindex = r_obi; \
+ rls = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLineSegment)); \
+ BLI_addtail(&rl->segments, rls);
+
+#define SELECT_RL(rl_num, llink, rlink, newrt) \
+ if (rta->rl[rl_num]) { \
+ old_rl = rta->rl[rl_num]; \
+ new_flag = old_rl->flags; \
+ old_rl->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ INCREASE_RL \
+ rl->l = (llink); \
+ rl->r = (rlink); \
+ rl->flags = new_flag; \
+ rl->object_ref = ob; \
+ rl->tl = ((old_rl->tl == rt) ? (newrt) : (old_rl->tl)); \
+ rl->tr = ((old_rl->tr == rt) ? (newrt) : (old_rl->tr)); \
+ lineart_add_line_to_list(rb, rl); \
+ }
+
+#define RELINK_RL(rl_num, newrt) \
+ if (rta->rl[rl_num]) { \
+ old_rl = rta->rl[rl_num]; \
+ old_rl->tl = ((old_rl->tl == rt) ? (newrt) : (old_rl->tl)); \
+ old_rl->tr = ((old_rl->tr == rt) ? (newrt) : (old_rl->tr)); \
+ }
+
+#define REMOVE_TRIANGLE_RL \
+ if (rta->rl[0]) { \
+ rta->rl[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ } \
+ if (rta->rl[1]) { \
+ rta->rl[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ } \
+ if (rta->rl[2]) { \
+ rta->rl[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ }
+
+ switch (in0 + in1 + in2) {
+ case 0: /* Triangle is visible. Ignore this triangle. */
+ return;
+ case 3:
+ /* Triangle completely behind near plane, throw it away
+ * also remove render lines form being computed. */
+ lineart_triangle_set_cull_flag(rt, LRT_CULL_DISCARD);
+ REMOVE_TRIANGLE_RL
+ return;
+ case 2:
+ /* Two points behind near plane, cut those and
+ * generate 2 new points, 3 lines and 1 triangle. */
+ lineart_triangle_set_cull_flag(rt, LRT_CULL_USED);
+
+ /* (!in0) means "when point 0 is visible".
+ * conditons for point 1, 2 are the same idea.
+ * 1-----|-------0
+ * | | ---
+ * | |---
+ * | ---|
+ * 2-- |
+ * (near)---------->(far)
+ * Will become:
+ * |N******0
+ * |* ***
+ * |N**
+ * |
+ * |
+ * (near)---------->(far)
+ */
+ if (!in0) {
+
+ /* Cut point for line 2---|-----0. */
+ sub_v3_v3v3_db(vv1, rt->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[2]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ /* Assign it to a new point. */
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[0]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+ rv[0].index = rt->v[2]->index;
+
+ /* Cut point for line 1---|-----0. */
+ sub_v3_v3v3_db(vv1, rt->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[1]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ /* Assign it to another new point. */
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[0]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+ rv[1].index = rt->v[1]->index;
+
+ /* New line connecting two new points. */
+ INCREASE_RL
+ if (allow_boundaries) {
+ rl->flags = LRT_EDGE_FLAG_CONTOUR;
+ lineart_prepend_line_direct(&rb->contours, rl);
+ }
+ /* Note: inverting rl->l/r (left/right point) doesn't matter as long as
+ * rt->rl and rt->v has the same sequence. and the winding direction
+ * can be either CW or CCW but needs to be consistent throughout the calculation.
+ */
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ /* Only one adjacent triangle, because the other side is the near plane. */
+ /* Use tl or tr doesn't matter. */
+ rl->tl = rt1;
+ rl->object_ref = ob;
+
+ /* New line connecting original point 0 and a new point, only when it's a selected line. */
+ SELECT_RL(2, rt->v[0], &rv[0], rt1)
+ /* New line connecting original point 0 and another new point. */
+ SELECT_RL(0, rt->v[0], &rv[1], rt1)
+
+ /* Re-assign triangle point array to two new points. */
+ rt1->v[0] = rt->v[0];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ lineart_triangle_post(rt1, rt);
+
+ v_count += 2;
+ t_count += 1;
+ }
+ else if (!in2) {
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[2]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+ rv[0].index = rt->v[0]->index;
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[1]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[2]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+ rv[1].index = rt->v[1]->index;
+
+ INCREASE_RL
+ if (allow_boundaries) {
+ rl->flags = LRT_EDGE_FLAG_CONTOUR;
+ lineart_prepend_line_direct(&rb->contours, rl);
+ }
+ rl->l = &rv[0];
+ rl->r = &rv[1];
+ rl->tl = rt1;
+ rl->object_ref = ob;
+
+ SELECT_RL(2, rt->v[2], &rv[0], rt1)
+ SELECT_RL(1, rt->v[2], &rv[1], rt1)
+
+ rt1->v[0] = &rv[0];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = rt->v[2];
+
+ lineart_triangle_post(rt1, rt);
+
+ v_count += 2;
+ t_count += 1;
+ }
+ else if (!in1) {
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[2]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[1]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+ rv[0].index = rt->v[2]->index;
+
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[1]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+ rv[1].index = rt->v[0]->index;
+
+ INCREASE_RL
+ if (allow_boundaries) {
+ rl->flags = LRT_EDGE_FLAG_CONTOUR;
+ lineart_prepend_line_direct(&rb->contours, rl);
+ }
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rl->object_ref = ob;
+
+ SELECT_RL(1, rt->v[1], &rv[0], rt1)
+ SELECT_RL(0, rt->v[1], &rv[1], rt1)
+
+ rt1->v[0] = &rv[0];
+ rt1->v[1] = rt->v[1];
+ rt1->v[2] = &rv[1];
+
+ lineart_triangle_post(rt1, rt);
+
+ v_count += 2;
+ t_count += 1;
+ }
+ break;
+ case 1:
+ /* One point behind near plane, cut those and
+ * generate 2 new points, 4 lines and 2 triangles. */
+ lineart_triangle_set_cull_flag(rt, LRT_CULL_USED);
+
+ /* (in0) means "when point 0 is invisible".
+ * conditons for point 1, 2 are the same idea.
+ * 0------|----------1
+ * -- | |
+ * ---| |
+ * |-- |
+ * | --- |
+ * | --- |
+ * | --2
+ * (near)---------->(far)
+ * Will become:
+ * |N*********1
+ * |* *** |
+ * |* *** |
+ * |N** |
+ * | *** |
+ * | *** |
+ * | **2
+ * (near)---------->(far)
+ */
+ if (in0) {
+ /* Cut point for line 0---|------1. */
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot2 / (dot1 + dot2);
+ /* Assign to a new point. */
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[0]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+ rv[0].index = rt->v[0]->index;
+
+ /* Cut point for line 0---|------2. */
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot2 / (dot1 + dot2);
+ /* Assign to aother new point. */
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[0]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+ rv[1].index = rt->v[0]->index;
+
+ /* New line connects two new points. */
+ INCREASE_RL
+ if (allow_boundaries) {
+ rl->flags = LRT_EDGE_FLAG_CONTOUR;
+ lineart_prepend_line_direct(&rb->contours, rl);
+ }
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rl->object_ref = ob;
+
+ /* New line connects new point 0 and old point 1,
+ * this is a border line.
+ */
+
+ SELECT_RL(0, rt->v[1], &rv[0], rt1)
+ SELECT_RL(2, rt->v[2], &rv[1], rt2)
+ RELINK_RL(1, rt2)
+
+ /* We now have one triangle closed. */
+ rt1->v[0] = rt->v[1];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+ /* Close the second triangle. */
+ rt2->v[0] = &rv[1];
+ rt2->v[1] = rt->v[1];
+ rt2->v[2] = rt->v[2];
+
+ lineart_triangle_post(rt1, rt);
+ lineart_triangle_post(rt2, rt);
+
+ v_count += 2;
+ t_count += 2;
+ }
+ else if (in1) {
+
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[2]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[1]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+ rv[0].index = rt->v[1]->index;
+
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[1]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+ rv[1].index = rt->v[1]->index;
+
+ INCREASE_RL
+ if (allow_boundaries) {
+ rl->flags = LRT_EDGE_FLAG_CONTOUR;
+ lineart_prepend_line_direct(&rb->contours, rl);
+ }
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rl->object_ref = ob;
+
+ SELECT_RL(1, rt->v[2], &rv[0], rt1)
+ SELECT_RL(0, rt->v[0], &rv[1], rt2)
+ RELINK_RL(2, rt2)
+
+ rt1->v[0] = rt->v[2];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ rt2->v[0] = &rv[1];
+ rt2->v[1] = rt->v[2];
+ rt2->v[2] = rt->v[0];
+
+ lineart_triangle_post(rt1, rt);
+ lineart_triangle_post(rt2, rt);
+
+ v_count += 2;
+ t_count += 2;
+ }
+ else if (in2) {
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[2]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+ rv[0].index = rt->v[2]->index;
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[1]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[2]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+ rv[1].index = rt->v[2]->index;
+
+ INCREASE_RL
+ if (allow_boundaries) {
+ rl->flags = LRT_EDGE_FLAG_CONTOUR;
+ lineart_prepend_line_direct(&rb->contours, rl);
+ }
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rl->object_ref = ob;
+
+ SELECT_RL(2, rt->v[0], &rv[0], rt1)
+ SELECT_RL(1, rt->v[1], &rv[1], rt2)
+ RELINK_RL(0, rt2)
+
+ rt1->v[0] = rt->v[0];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ rt2->v[0] = &rv[1];
+ rt2->v[1] = rt->v[0];
+ rt2->v[2] = rt->v[1];
+
+ lineart_triangle_post(rt1, rt);
+ lineart_triangle_post(rt2, rt);
+
+ v_count += 2;
+ t_count += 2;
+ }
+ break;
+ }
+ *r_v_count = v_count;
+ *r_l_count = l_count;
+ *r_t_count = t_count;
+
+#undef INCREASE_RL
+#undef SELECT_RL
+#undef RELINK_RL
+#undef REMOVE_TRIANGLE_RL
+}
+
+/* This function cuts triangles with near- or far-plane. Setting clip_far = true for cutting with
+ * far-plane. For triangles that's crossing the plane, it will generate new 1 or 2 triangles with
+ * new topology that represents the trimmed triangle. (which then became a triangle or a square
+ * formed by two triangles)
+ */
+static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
+{
+ LineartTriangle *rt;
+ LineartElementLinkNode *veln, *teln, *leln;
+ double(*vp)[4] = rb->view_projection;
+ int i;
+ int v_count = 0, t_count = 0, l_count = 0;
+ Object *ob;
+ bool allow_boundaries = rb->allow_boundaries;
+ double cam_pos[3];
+ double clip_start = rb->near_clip, clip_end = rb->far_clip;
+ double view_dir[3], clip_advance[3];
+
+ copy_v3_v3_db(view_dir, rb->view_vector);
+ copy_v3_v3_db(clip_advance, rb->view_vector);
+ copy_v3_v3_db(cam_pos, rb->camera_pos);
+
+ if (clip_far) {
+ /* Move starting point to end plane. */
+ mul_v3db_db(clip_advance, -clip_end);
+ add_v3_v3_db(cam_pos, clip_advance);
+
+ /* "reverse looking". */
+ mul_v3db_db(view_dir, -1.0f);
+ }
+ else {
+ /* Clip Near. */
+ mul_v3db_db(clip_advance, -clip_start);
+ add_v3_v3_db(cam_pos, clip_advance);
+ }
+
+ veln = lineart_memory_get_vert_space(rb);
+ teln = lineart_memory_get_triangle_space(rb);
+ leln = lineart_memory_get_line_space(rb);
+
+ /* Additional memory space for storing generated points and triangles. */
+#define LRT_CULL_ENSURE_MEMORY \
+ if (v_count > 60) { \
+ veln->element_count = v_count; \
+ veln = lineart_memory_get_vert_space(rb); \
+ v_count = 0; \
+ } \
+ if (t_count > 60) { \
+ teln->element_count = t_count; \
+ teln = lineart_memory_get_triangle_space(rb); \
+ t_count = 0; \
+ } \
+ if (l_count > 60) { \
+ leln->element_count = l_count; \
+ leln = lineart_memory_get_line_space(rb); \
+ l_count = 0; \
+ }
+
+#define LRT_CULL_DECIDE_INSIDE \
+ /* These three represents points that are in the clipping range or not*/ \
+ in0 = 0, in1 = 0, in2 = 0; \
+ if (clip_far) { \
+ /* Point outside far plane. */ \
+ if (rt->v[0]->fbcoord[use_w] > clip_end) { \
+ in0 = 1; \
+ } \
+ if (rt->v[1]->fbcoord[use_w] > clip_end) { \
+ in1 = 1; \
+ } \
+ if (rt->v[2]->fbcoord[use_w] > clip_end) { \
+ in2 = 1; \
+ } \
+ } \
+ else { \
+ /* Point inside near plane. */ \
+ if (rt->v[0]->fbcoord[use_w] < clip_start) { \
+ in0 = 1; \
+ } \
+ if (rt->v[1]->fbcoord[use_w] < clip_start) { \
+ in1 = 1; \
+ } \
+ if (rt->v[2]->fbcoord[use_w] < clip_start) { \
+ in2 = 1; \
+ } \
+ }
+
+ int use_w = 3;
+ int in0 = 0, in1 = 0, in2 = 0;
+
+ if (!rb->cam_is_persp) {
+ clip_start = -1;
+ clip_end = 1;
+ use_w = 2;
+ }
+
+ /* Then go through all the other triangles. */
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ if (reln->flags & LRT_ELEMENT_IS_ADDITIONAL) {
+ continue;
+ }
+ ob = reln->object_ref;
+ for (i = 0; i < reln->element_count; i++) {
+ /* Select the triangle in the array. */
+ rt = (void *)(((unsigned char *)reln->pointer) + rb->triangle_size * i);
+
+ LRT_CULL_DECIDE_INSIDE
+ LRT_CULL_ENSURE_MEMORY
+ lineart_triangle_cull_single(rb,
+ rt,
+ in0,
+ in1,
+ in2,
+ cam_pos,
+ view_dir,
+ allow_boundaries,
+ vp,
+ ob,
+ &v_count,
+ &l_count,
+ &t_count,
+ veln,
+ leln,
+ teln);
+ }
+ teln->element_count = t_count;
+ veln->element_count = v_count;
+ }
+
+#undef LRT_CULL_ENSURE_MEMORY
+#undef LRT_CULL_DECIDE_INSIDE
+}
+
+/* Adjacent data is only used during the initial stages of computing. So we can free it using this
+ * function when it is not needed anymore. */
+static void lineart_main_free_adjacent_data(LineartRenderBuffer *rb)
+{
+ LinkData *ld;
+ while ((ld = BLI_pophead(&rb->triangle_adjacent_pointers)) != NULL) {
+ MEM_freeN(ld->data);
+ }
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ LineartTriangle *rt = reln->pointer;
+ int i;
+ for (i = 0; i < reln->element_count; i++) {
+ /* See definition of rt->intersecting_verts and the usage in
+ * lineart_geometry_object_load() for detailes. */
+ rt->intersecting_verts = NULL;
+ rt = (LineartTriangle *)(((unsigned char *)rt) + rb->triangle_size);
+ }
+ }
+}
+
+static void lineart_main_perspective_division(LineartRenderBuffer *rb)
+{
+ LineartVert *rv;
+ int i;
+
+ if (!rb->cam_is_persp) {
+ return;
+ }
+
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->vertex_buffer_pointers) {
+ rv = reln->pointer;
+ for (i = 0; i < reln->element_count; i++) {
+ /* Do not divide Z, we use Z to back transform cut points in later chaining process. */
+ rv[i].fbcoord[0] /= rv[i].fbcoord[3];
+ rv[i].fbcoord[1] /= rv[i].fbcoord[3];
+ /* Re-map z into (0-1) range, because we no longer need NDC (Normalized Device Coordinates)
+ * at the moment.
+ * The algorithm currently doesn't need Z for operation, we use W instead. If Z is needed in
+ * the future, the line below correctly transforms it to view space coordinates. */
+ /* rv[i].fbcoord[2] = -2 * rv[i].fbcoord[2] / (far - near) - (far + near) / (far - near);. */
+ rv[i].fbcoord[0] -= rb->shift_x * 2;
+ rv[i].fbcoord[1] -= rb->shift_y * 2;
+ }
+ }
+}
+
+/* Transform a single vert to it's viewing position. */
+static void lineart_vert_transform(
+ BMVert *v, int index, LineartVert *RvBuf, double (*mv_mat)[4], double (*mvp_mat)[4])
+{
+ double co[4];
+ LineartVert *rv = &RvBuf[index];
+ copy_v3db_v3fl(co, v->co);
+ mul_v3_m4v3_db(rv->gloc, mv_mat, co);
+ mul_v4_m4v3_db(rv->fbcoord, mvp_mat, co);
+}
+
+/* Because we have a variable size for LineartTriangle, we need an access helper. See
+ * LineartTriangleThread for more info. */
+static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
+ LineartTriangle *rt_array,
+ int index)
+{
+ char *b = (char *)rt_array;
+ b += (index * rb->triangle_size);
+ return (LineartTriangle *)b;
+}
+
+static char lineart_identify_feature_line(LineartRenderBuffer *rb,
+ BMEdge *e,
+ LineartTriangle *rt_array,
+ LineartVert *rv_array,
+ float crease_threshold,
+ bool no_crease,
+ bool count_freestyle,
+ BMesh *bm_if_freestyle)
+{
+ BMLoop *ll, *lr = NULL;
+ ll = e->l;
+ if (ll) {
+ lr = e->l->radial_next;
+ }
+
+ if (ll == lr || !lr) {
+ return LRT_EDGE_FLAG_CONTOUR;
+ }
+
+ LineartTriangle *rt1, *rt2;
+ LineartVert *l;
+
+ /* The mesh should already be triangulated now, so we can assume each face is a triangle. */
+ rt1 = lineart_triangle_from_index(rb, rt_array, BM_elem_index_get(ll->f));
+ rt2 = lineart_triangle_from_index(rb, rt_array, BM_elem_index_get(lr->f));
+
+ l = &rv_array[BM_elem_index_get(e->v1)];
+
+ double vv[3];
+ double *view_vector = vv;
+ double dot_1 = 0, dot_2 = 0;
+ double result;
+ FreestyleEdge *fe;
+
+ if (rb->cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos);
+ }
+ else {
+ view_vector = rb->view_vector;
+ }
+
+ dot_1 = dot_v3v3_db(view_vector, rt1->gn);
+ dot_2 = dot_v3v3_db(view_vector, rt2->gn);
+
+ if ((result = dot_1 * dot_2) < 0 && (dot_1 + dot_2)) {
+ return LRT_EDGE_FLAG_CONTOUR;
+ }
+
+ if (rb->use_crease && (dot_v3v3_db(rt1->gn, rt2->gn) < crease_threshold)) {
+ if (!no_crease) {
+ return LRT_EDGE_FLAG_CREASE;
+ }
+ }
+ else if (rb->use_material && (ll->f->mat_nr != lr->f->mat_nr)) {
+ return LRT_EDGE_FLAG_MATERIAL;
+ }
+ else if (count_freestyle && rb->use_edge_marks) {
+ fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE);
+ if (fe->flag & FREESTYLE_EDGE_MARK) {
+ return LRT_EDGE_FLAG_EDGE_MARK;
+ }
+ }
+ return 0;
+}
+
+static void lineart_add_line_to_list(LineartRenderBuffer *rb, LineartLine *rl)
+{
+ switch (rl->flags) {
+ case LRT_EDGE_FLAG_CONTOUR:
+ lineart_prepend_line_direct(&rb->contours, rl);
+ break;
+ case LRT_EDGE_FLAG_CREASE:
+ lineart_prepend_line_direct(&rb->crease_lines, rl);
+ break;
+ case LRT_EDGE_FLAG_MATERIAL:
+ lineart_prepend_line_direct(&rb->material_lines, rl);
+ break;
+ case LRT_EDGE_FLAG_EDGE_MARK:
+ lineart_prepend_line_direct(&rb->edge_marks, rl);
+ break;
+ case LRT_EDGE_FLAG_INTERSECTION:
+ lineart_prepend_line_direct(&rb->intersection_lines, rl);
+ break;
+ }
+}
+
+static void lineart_triangle_adjacent_assign(LineartTriangle *rt,
+ LineartTriangleAdjacent *rta,
+ LineartLine *rl)
+{
+ if (lineart_line_match(rt, rl, 0, 1)) {
+ rta->rl[0] = rl;
+ }
+ else if (lineart_line_match(rt, rl, 1, 2)) {
+ rta->rl[1] = rl;
+ }
+ else if (lineart_line_match(rt, rl, 2, 0)) {
+ rta->rl[2] = rl;
+ }
+}
+
+static void lineart_geometry_object_load(Depsgraph *dg,
+ Object *ob,
+ double (*mv_mat)[4],
+ double (*mvp_mat)[4],
+ LineartRenderBuffer *rb,
+ int override_usage,
+ int *global_vindex)
+{
+ BMesh *bm;
+ BMVert *v;
+ BMFace *f;
+ BMEdge *e;
+ BMLoop *loop;
+ LineartLine *rl;
+ LineartTriangle *rt;
+ LineartTriangleAdjacent *orta;
+ double new_mvp[4][4], new_mv[4][4], normal[4][4];
+ float imat[4][4];
+ LineartElementLinkNode *reln;
+ LineartVert *orv;
+ LineartLine *orl;
+ LineartTriangle *ort;
+ Object *orig_ob;
+ int CanFindFreestyle = 0;
+ int i, global_i = (*global_vindex);
+ Mesh *use_mesh;
+ float use_crease = 0;
+
+ int usage = override_usage ? override_usage : ob->lineart.usage;
+
+#define LRT_MESH_FINISH \
+ BM_mesh_free(bm); \
+ if (ob->type != OB_MESH) { \
+ BKE_mesh_free(use_mesh); \
+ MEM_freeN(use_mesh); \
+ }
+
+ if (usage == OBJECT_LRT_EXCLUDE) {
+ return;
+ }
+
+ if (ob->type == OB_MESH || ob->type == OB_MBALL || ob->type == OB_CURVE || ob->type == OB_SURF ||
+ ob->type == OB_FONT) {
+
+ if (ob->type == OB_MESH) {
+ use_mesh = DEG_get_evaluated_object(dg, ob)->data;
+ }
+ else {
+ use_mesh = BKE_mesh_new_from_object(NULL, ob, false);
+ }
+
+ /* In case we can not get any mesh geometry data from the object */
+ if (!use_mesh) {
+ return;
+ }
+
+ /* First we need to prepare the matrix used for transforming this specific object. */
+ mul_m4db_m4db_m4fl_uniq(new_mvp, mvp_mat, ob->obmat);
+ mul_m4db_m4db_m4fl_uniq(new_mv, mv_mat, ob->obmat);
+
+ invert_m4_m4(imat, ob->obmat);
+ transpose_m4(imat);
+ copy_m4d_m4(normal, imat);
+
+ if (use_mesh->edit_mesh) {
+ /* Do not use edit_mesh directly because we will modify it, so create a copy. */
+ bm = BM_mesh_copy(use_mesh->edit_mesh->bm);
+ }
+ else {
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(((Mesh *)(use_mesh)));
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+ BM_mesh_bm_from_me(bm,
+ use_mesh,
+ &((struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ }
+
+ if (rb->remove_doubles) {
+ BMEditMesh *em = BKE_editmesh_create(bm, false);
+ BMOperator findop, weldop;
+
+ /* See bmesh_opdefines.c and bmesh_operators.c for op names and argument formatting. */
+ BMO_op_initf(bm, &findop, BMO_FLAG_DEFAULTS, "find_doubles verts=%av dist=%f", 0.0001);
+
+ BMO_op_exec(bm, &findop);
+
+ /* Weld the vertices. */
+ BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
+ BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
+ BMO_op_exec(bm, &weldop);
+
+ BMO_op_finish(bm, &findop);
+ BMO_op_finish(bm, &weldop);
+
+ MEM_freeN(em);
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false);
+ BM_mesh_triangulate(
+ bm, MOD_TRIANGULATE_QUAD_FIXED, MOD_TRIANGULATE_NGON_BEAUTY, 4, false, NULL, NULL, NULL);
+ BM_mesh_normals_update(bm);
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+
+ if (CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
+ CanFindFreestyle = 1;
+ }
+
+ /* Only allocate memory for verts and tris as we don't know how many lines we will generate
+ * yet. */
+ orv = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartVert) * bm->totvert);
+ ort = lineart_mem_aquire(&rb->render_data_pool, bm->totface * rb->triangle_size);
+
+ orig_ob = ob->id.orig_id ? (Object *)ob->id.orig_id : ob;
+
+ reln = lineart_list_append_pointer_pool_sized(
+ &rb->vertex_buffer_pointers, &rb->render_data_pool, orv, sizeof(LineartElementLinkNode));
+ reln->element_count = bm->totvert;
+ reln->object_ref = orig_ob;
+
+ if (ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
+ use_crease = cosf(M_PI - ob->lineart.crease_threshold);
+ }
+ else {
+ use_crease = rb->crease_threshold;
+ }
+
+ /* FIXME Yiming: Hack for getting clean 3D text, the seam that extruded text object creates
+ * erroneous detection on creases. Future configuration should allow options. */
+ if (ob->type == OB_FONT) {
+ reln->flags |= LRT_ELEMENT_BORDER_ONLY;
+ }
+
+ reln = lineart_list_append_pointer_pool_sized(
+ &rb->triangle_buffer_pointers, &rb->render_data_pool, ort, sizeof(LineartElementLinkNode));
+ reln->element_count = bm->totface;
+ reln->object_ref = orig_ob;
+ reln->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
+
+ /* Note this memory is not from pool, will be deleted after culling. */
+ orta = MEM_callocN(sizeof(LineartTriangleAdjacent) * bm->totface, "LineartTriangleAdjacent");
+ /* Link is minimal so we use pool anyway. */
+ lineart_list_append_pointer_pool(&rb->triangle_adjacent_pointers, &rb->render_data_pool, orta);
+
+ for (i = 0; i < bm->totvert; i++) {
+ v = BM_vert_at_index(bm, i);
+ lineart_vert_transform(v, i, orv, new_mv, new_mvp);
+ orv[i].index = i + global_i;
+ }
+ /* Register a global index increment. See lineart_triangle_share_edge() and
+ * lineart_main_load_geometries() for detailes. It's okay that global_vindex might eventually
+ * overflow, in such large scene it's virtually impossible for two vertex of the same numeric
+ * index to come close together. */
+ (*global_vindex) += bm->totvert;
+
+ rt = ort;
+ for (i = 0; i < bm->totface; i++) {
+ f = BM_face_at_index(bm, i);
+
+ loop = f->l_first;
+ rt->v[0] = &orv[BM_elem_index_get(loop->v)];
+ loop = loop->next;
+ rt->v[1] = &orv[BM_elem_index_get(loop->v)];
+ loop = loop->next;
+ rt->v[2] = &orv[BM_elem_index_get(loop->v)];
+
+ /* Transparency bit assignment. */
+ Material *mat = BKE_object_material_get(ob, f->mat_nr + 1);
+ rt->transparency_mask = ((mat && (mat->lineart.flags & LRT_MATERIAL_TRANSPARENCY_ENABLED)) ?
+ mat->lineart.transparency_mask :
+ 0);
+
+ double gn[3];
+ copy_v3db_v3fl(gn, f->no);
+ mul_v3_mat3_m4v3_db(rt->gn, normal, gn);
+ normalize_v3_db(rt->gn);
+
+ if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
+ rt->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
+ }
+ else if (usage == OBJECT_LRT_NO_INTERSECTION || usage == OBJECT_LRT_OCCLUSION_ONLY) {
+ rt->flags |= LRT_TRIANGLE_NO_INTERSECTION;
+ }
+
+ /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
+ rt->intersecting_verts = (void *)&orta[i];
+
+ rt = (LineartTriangle *)(((unsigned char *)rt) + rb->triangle_size);
+ }
+
+ /* Use BM_ELEM_TAG in f->head.hflag to store needed faces in the first iteration. */
+
+ int allocate_rl = 0;
+ for (i = 0; i < bm->totedge; i++) {
+ e = BM_edge_at_index(bm, i);
+
+ /* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */
+ char eflag = lineart_identify_feature_line(
+ rb, e, ort, orv, use_crease, ob->type == OB_FONT, CanFindFreestyle, bm);
+ if (eflag) {
+ /* Only allocate for feature lines (instead of all lines) to save memory. */
+ allocate_rl++;
+ }
+ /* Here we just use bm's flag for when loading actual lines, then we don't need to call
+ * lineart_identify_feature_line() again, e->head.hflag deleted after loading anyway. Always
+ * set the flag, so hflag stays 0 for lines that are not feature lines. */
+ e->head.hflag = eflag;
+ }
+
+ orl = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLine) * allocate_rl);
+ reln = lineart_list_append_pointer_pool_sized(
+ &rb->line_buffer_pointers, &rb->render_data_pool, orl, sizeof(LineartElementLinkNode));
+ reln->element_count = allocate_rl;
+ reln->object_ref = orig_ob;
+
+ rl = orl;
+ for (i = 0; i < bm->totedge; i++) {
+ e = BM_edge_at_index(bm, i);
+
+ /* Not a feature line, so we skip. */
+ if (!e->head.hflag) {
+ continue;
+ }
+
+ rl->l = &orv[BM_elem_index_get(e->v1)];
+ rl->r = &orv[BM_elem_index_get(e->v2)];
+ rl->l_obindex = rl->l->index - global_i;
+ rl->r_obindex = rl->r->index - global_i;
+ if (e->l) {
+ int findex = BM_elem_index_get(e->l->f);
+ rl->tl = lineart_triangle_from_index(rb, ort, findex);
+ lineart_triangle_adjacent_assign(rl->tl, &orta[findex], rl);
+ if (e->l->radial_next && e->l->radial_next != e->l) {
+ findex = BM_elem_index_get(e->l->radial_next->f);
+ rl->tr = lineart_triangle_from_index(rb, ort, findex);
+ lineart_triangle_adjacent_assign(rl->tr, &orta[findex], rl);
+ }
+ }
+ rl->flags = e->head.hflag;
+ rl->object_ref = orig_ob;
+
+ LineartLineSegment *rls = lineart_mem_aquire(&rb->render_data_pool,
+ sizeof(LineartLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ if (usage == OBJECT_LRT_INHERENT || usage == OBJECT_LRT_INCLUDE ||
+ usage == OBJECT_LRT_NO_INTERSECTION) {
+ lineart_add_line_to_list(rb, rl);
+ }
+
+ rl++;
+ }
+
+ LRT_MESH_FINISH
+ }
+
+#undef LRT_MESH_FINISH
+}
+
+/* See if this object in such collection is used for generating line art,
+ * Disabling a collection for line art will diable all objects inside. */
+static int lineart_usage_check(Collection *c, Object *ob)
+{
+
+ if (!c) {
+ return OBJECT_LRT_INHERENT;
+ }
+
+ int object_is_used = (ob->lineart.usage != OBJECT_LRT_INHERENT);
+
+ if (object_is_used) {
+ return ob->lineart.usage;
+ }
+
+ if (c->children.first == NULL) {
+ if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
+ if (ob->lineart.usage == OBJECT_LRT_INHERENT) {
+ switch (c->lineart_usage) {
+ case COLLECTION_LRT_OCCLUSION_ONLY:
+ return OBJECT_LRT_OCCLUSION_ONLY;
+ case COLLECTION_LRT_EXCLUDE:
+ return OBJECT_LRT_EXCLUDE;
+ case COLLECTION_LRT_INTERSECTION_ONLY:
+ return OBJECT_LRT_INTERSECTION_ONLY;
+ case COLLECTION_LRT_NO_INTERSECTION:
+ return OBJECT_LRT_NO_INTERSECTION;
+ }
+ return OBJECT_LRT_INHERENT;
+ }
+ return ob->lineart.usage;
+ }
+ return OBJECT_LRT_INHERENT;
+ }
+
+ LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
+ int result = lineart_usage_check(cc->collection, ob);
+ if (result > OBJECT_LRT_INHERENT) {
+ return result;
+ }
+ }
+
+ return OBJECT_LRT_INHERENT;
+}
+
+static void lineart_main_load_geometries(
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *camera /* Still use camera arg for convenience. */,
+ LineartRenderBuffer *rb,
+ bool allow_duplicates)
+{
+ double proj[4][4], view[4][4], result[4][4];
+ float inv[4][4];
+
+ Camera *cam = camera->data;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ double fov = focallength_to_fov(cam->lens, sensor);
+
+ double asp = ((double)rb->w / (double)rb->h);
+
+ if (cam->type == CAM_PERSP) {
+ if (asp < 1) {
+ fov /= asp;
+ }
+ lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
+ }
+ else if (cam->type == CAM_ORTHO) {
+ double w = cam->ortho_scale / 2;
+ lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
+ }
+ invert_m4_m4(inv, rb->cam_obmat);
+ mul_m4db_m4db_m4fl_uniq(result, proj, inv);
+ copy_m4_m4_db(proj, result);
+ copy_m4_m4_db(rb->view_projection, proj);
+
+ unit_m4_db(view);
+
+ BLI_listbase_clear(&rb->triangle_buffer_pointers);
+ BLI_listbase_clear(&rb->vertex_buffer_pointers);
+
+ int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE;
+
+ /* Instance duplicated & particles. */
+ if (allow_duplicates) {
+ flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
+ }
+
+ /* This is to serialize vertex index in the whole scene, so lineart_triangle_share_edge() can
+ * work properly from the lack of triangle adjacent info. */
+ int global_i = 0;
+
+ DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
+ int usage = lineart_usage_check(scene->master_collection, ob);
+
+ lineart_geometry_object_load(depsgraph, ob, view, proj, rb, usage, &global_i);
+ }
+ DEG_OBJECT_ITER_END;
+}
+
+/* Returns the two other verts of the triangle given a vertex. Returns false if the given vertex
+ * doesn't belong to this triangle. */
+static bool lineart_triangle_get_other_verts(const LineartTriangle *rt,
+ const LineartVert *rv,
+ LineartVert **l,
+ LineartVert **r)
+{
+ if (rt->v[0] == rv) {
+ *l = rt->v[1];
+ *r = rt->v[2];
+ return true;
+ }
+ if (rt->v[1] == rv) {
+ *l = rt->v[2];
+ *r = rt->v[0];
+ return true;
+ }
+ if (rt->v[2] == rv) {
+ *l = rt->v[0];
+ *r = rt->v[1];
+ return true;
+ }
+ return false;
+}
+
+static bool lineart_edge_from_triangle(const LineartTriangle *rt,
+ const LineartLine *rl,
+ bool allow_overlapping_edges)
+{
+ /* Normally we just determine from the pointer address. */
+ if (rl->tl == rt || rl->tr == rt) {
+ return true;
+ }
+ /* If allows overlapping, then we compare the vertex coordinates one by one to determine if one
+ * edge is from specific triangle. This is slower but can handle edge split cases very well. */
+ if (allow_overlapping_edges) {
+#define LRT_TRI_SAME_POINT(rt, i, pt) \
+ ((LRT_DOUBLE_CLOSE_ENOUGH(rt->v[i]->gloc[0], pt->gloc[0]) && \
+ LRT_DOUBLE_CLOSE_ENOUGH(rt->v[i]->gloc[1], pt->gloc[1]) && \
+ LRT_DOUBLE_CLOSE_ENOUGH(rt->v[i]->gloc[2], pt->gloc[2])) || \
+ (LRT_DOUBLE_CLOSE_ENOUGH(rt->v[i]->gloc[0], pt->gloc[0]) && \
+ LRT_DOUBLE_CLOSE_ENOUGH(rt->v[i]->gloc[1], pt->gloc[1]) && \
+ LRT_DOUBLE_CLOSE_ENOUGH(rt->v[i]->gloc[2], pt->gloc[2])))
+ if ((LRT_TRI_SAME_POINT(rt, 0, rl->l) || LRT_TRI_SAME_POINT(rt, 1, rl->l) ||
+ LRT_TRI_SAME_POINT(rt, 2, rl->l)) &&
+ (LRT_TRI_SAME_POINT(rt, 0, rl->r) || LRT_TRI_SAME_POINT(rt, 1, rl->r) ||
+ LRT_TRI_SAME_POINT(rt, 2, rl->r))) {
+ return true;
+ }
+#undef LRT_TRI_SAME_POINT
+ }
+ return false;
+}
+
+/* Sorting three intersection points from min to max,
+ * the order for each intersection is set in lst[0] to lst[2].*/
+#define INTERSECT_SORT_MIN_TO_MAX_3(ia, ib, ic, lst) \
+ { \
+ lst[0] = LRT_MIN3_INDEX(ia, ib, ic); \
+ lst[1] = (((ia <= ib && ib <= ic) || (ic <= ib && ib <= ia)) ? \
+ 1 : \
+ (((ic <= ia && ia <= ib) || (ib < ia && ia <= ic)) ? 0 : 2)); \
+ lst[2] = LRT_MAX3_INDEX(ia, ib, ic); \
+ }
+
+/* ia ib ic are ordered. */
+#define INTERSECT_JUST_GREATER(is, order, num, index) \
+ { \
+ index = (num < is[order[0]] ? \
+ order[0] : \
+ (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : order[2]))); \
+ }
+
+/* ia ib ic are ordered. */
+#define INTERSECT_JUST_SMALLER(is, order, num, index) \
+ { \
+ index = (num > is[order[2]] ? \
+ order[2] : \
+ (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : order[0]))); \
+ }
+
+/* This is the main function to calculate
+ * the occlusion status between 1(one) triangle and 1(one) line.
+ * if returns true, then from/to will carry the occludded segments
+ * in ratio from rl->l to rl->r. The line is later cut with these two values.
+ */
+static bool lineart_triangle_line_image_space_occlusion(SpinLock *UNUSED(spl),
+ const LineartTriangle *rt,
+ const LineartLine *rl,
+ const double *override_camera_loc,
+ const bool override_cam_is_persp,
+ const bool allow_overlapping_edges,
+ const double vp[4][4],
+ const double *camera_dir,
+ const float cam_shift_x,
+ const float cam_shift_y,
+ double *from,
+ double *to)
+{
+ double is[3] = {0};
+ int order[3];
+ int LCross = -1, RCross = -1;
+ int a, b, c;
+ int st_l = 0, st_r = 0;
+
+ double Lv[3];
+ double Rv[3];
+ double vd4[4];
+ double Cv[3];
+ double dot_l, dot_r, dot_la, dot_ra;
+ double dot_f;
+ double gloc[4], trans[4];
+ double cut = -1;
+
+ double *LFBC = rl->l->fbcoord, *RFBC = rl->r->fbcoord, *FBC0 = rt->v[0]->fbcoord,
+ *FBC1 = rt->v[1]->fbcoord, *FBC2 = rt->v[2]->fbcoord;
+
+ /* Overlapping not possible, return early. */
+ if ((MAX3(FBC0[0], FBC1[0], FBC2[0]) < MIN2(LFBC[0], RFBC[0])) ||
+ (MIN3(FBC0[0], FBC1[0], FBC2[0]) > MAX2(LFBC[0], RFBC[0])) ||
+ (MAX3(FBC0[1], FBC1[1], FBC2[1]) < MIN2(LFBC[1], RFBC[1])) ||
+ (MIN3(FBC0[1], FBC1[1], FBC2[1]) > MAX2(LFBC[1], RFBC[1])) ||
+ (MIN3(FBC0[3], FBC1[3], FBC2[3]) > MAX2(LFBC[3], RFBC[3]))) {
+ return false;
+ }
+
+ /* If the the line is one of the edge in the triangle, then it's not occludded. */
+ if (lineart_edge_from_triangle(rt, rl, allow_overlapping_edges)) {
+ return false;
+ }
+
+ /* Check if the line visually crosses one of the edge in the triangle. */
+ a = lineart_LineIntersectTest2d(LFBC, RFBC, FBC0, FBC1, &is[0]);
+ b = lineart_LineIntersectTest2d(LFBC, RFBC, FBC1, FBC2, &is[1]);
+ c = lineart_LineIntersectTest2d(LFBC, RFBC, FBC2, FBC0, &is[2]);
+
+ /* Sort the intersection distance. */
+ INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order);
+
+ sub_v3_v3v3_db(Lv, rl->l->gloc, rt->v[0]->gloc);
+ sub_v3_v3v3_db(Rv, rl->r->gloc, rt->v[0]->gloc);
+
+ copy_v3_v3_db(Cv, camera_dir);
+
+ if (override_cam_is_persp) {
+ copy_v3_v3_db(vd4, override_camera_loc);
+ }
+ else {
+ copy_v4_v4_db(vd4, override_camera_loc);
+ }
+ if (override_cam_is_persp) {
+ sub_v3_v3v3_db(Cv, vd4, rt->v[0]->gloc);
+ }
+
+ dot_l = dot_v3v3_db(Lv, rt->gn);
+ dot_r = dot_v3v3_db(Rv, rt->gn);
+ dot_f = dot_v3v3_db(Cv, rt->gn);
+
+ if (!dot_f) {
+ return false;
+ }
+
+ if (!a && !b && !c) {
+ if (!(st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) &&
+ !(st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) {
+ return 0; /* Intersection point is not inside triangle. */
+ }
+ }
+
+ st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
+ st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
+
+ /* Determine the cut position. */
+
+ dot_la = fabs(dot_l);
+ if (dot_la < DBL_EPSILON) {
+ dot_la = 0;
+ dot_l = 0;
+ }
+ dot_ra = fabs(dot_r);
+ if (dot_ra < DBL_EPSILON) {
+ dot_ra = 0;
+ dot_r = 0;
+ }
+ if (dot_l - dot_r == 0) {
+ cut = 100000;
+ }
+ else if (dot_l * dot_r <= 0) {
+ cut = dot_la / fabs(dot_l - dot_r);
+ }
+ else {
+ cut = fabs(dot_r + dot_l) / fabs(dot_l - dot_r);
+ cut = dot_ra > dot_la ? 1 - cut : cut;
+ }
+
+ /* Transform the cut from geometry space to image space. */
+ if (override_cam_is_persp) {
+ interp_v3_v3v3_db(gloc, rl->l->gloc, rl->r->gloc, cut);
+ mul_v4_m4v3_db(trans, vp, gloc);
+ mul_v3db_db(trans, (1 / trans[3]));
+ }
+ else {
+ interp_v3_v3v3_db(trans, rl->l->fbcoord, rl->r->fbcoord, cut);
+ }
+ trans[0] -= cam_shift_x * 2;
+ trans[1] -= cam_shift_y * 2;
+
+ /* To accomodate k=0 and k=inf (vertical) lines. here the cut is in image space. */
+ if (fabs(rl->l->fbcoord[0] - rl->r->fbcoord[0]) > fabs(rl->l->fbcoord[1] - rl->r->fbcoord[1])) {
+ cut = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], trans[0]);
+ }
+ else {
+ cut = ratiod(rl->l->fbcoord[1], rl->r->fbcoord[1], trans[1]);
+ }
+
+ /* Determine the pair of edges that the line has crossed. */
+
+ if (st_l == 2) {
+ if (st_r == 2) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (st_r == 1) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (st_r == 0) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 0, RCross);
+ }
+ }
+ else if (st_l == 1) {
+ if (st_r == 2) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (st_r == 1) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (st_r == 0) {
+ INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross);
+ if (LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ }
+ else {
+ INTERSECT_JUST_SMALLER(is, order, -DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, RCross);
+ }
+ }
+ }
+ else if (st_l == 0) {
+ if (st_r == 2) {
+ INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (st_r == 1) {
+ INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
+ if (LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else {
+ INTERSECT_JUST_SMALLER(is, order, 1 + DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 + DBL_TRIANGLE_LIM, RCross);
+ }
+ }
+ else if (st_r == 0) {
+ INTERSECT_JUST_GREATER(is, order, 0, LCross);
+ if (LRT_ABC(LCross) && is[LCross] > 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ else {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ }
+ }
+
+ double LF = dot_l * dot_f, RF = dot_r * dot_f;
+
+ /* Determine the start and end point of image space cut on a line. */
+ if (LF <= 0 && RF <= 0 && (dot_l || dot_r)) {
+ *from = MAX2(0, is[LCross]);
+ *to = MIN2(1, is[RCross]);
+ if (*from >= *to) {
+ return false;
+ }
+ return true;
+ }
+ if (LF >= 0 && RF <= 0 && (dot_l || dot_r)) {
+ *from = MAX2(cut, is[LCross]);
+ *to = MIN2(1, is[RCross]);
+ if (*from >= *to) {
+ return false;
+ }
+ return true;
+ }
+ if (LF <= 0 && RF >= 0 && (dot_l || dot_r)) {
+ *from = MAX2(0, is[LCross]);
+ *to = MIN2(cut, is[RCross]);
+ if (*from >= *to) {
+ return false;
+ }
+ return true;
+ }
+
+ /* Unlikely, but here's the default failed value if anything fall through. */
+ return false;
+}
+
+#undef INTERSECT_SORT_MIN_TO_MAX_3
+#undef INTERSECT_JUST_GREATER
+#undef INTERSECT_JUST_SMALLER
+
+/* At this stage of the computation we don't have triangle adjacent info anymore, so we can only
+ * compare the global vert index. */
+static bool lineart_triangle_share_edge(const LineartTriangle *l, const LineartTriangle *r)
+{
+ if (l->v[0]->index == r->v[0]->index) {
+ if (l->v[1]->index == r->v[1]->index || l->v[1]->index == r->v[2]->index ||
+ l->v[2]->index == r->v[2]->index || l->v[2]->index == r->v[1]->index) {
+ return true;
+ }
+ }
+ if (l->v[0]->index == r->v[1]->index) {
+ if (l->v[1]->index == r->v[0]->index || l->v[1]->index == r->v[2]->index ||
+ l->v[2]->index == r->v[2]->index || l->v[2]->index == r->v[0]->index) {
+ return true;
+ }
+ }
+ if (l->v[0]->index == r->v[2]->index) {
+ if (l->v[1]->index == r->v[1]->index || l->v[1]->index == r->v[0]->index ||
+ l->v[2]->index == r->v[0]->index || l->v[2]->index == r->v[1]->index) {
+ return true;
+ }
+ }
+ if (l->v[1]->index == r->v[0]->index) {
+ if (l->v[2]->index == r->v[1]->index || l->v[2]->index == r->v[2]->index ||
+ l->v[0]->index == r->v[2]->index || l->v[0]->index == r->v[1]->index) {
+ return true;
+ }
+ }
+ if (l->v[1]->index == r->v[1]->index) {
+ if (l->v[2]->index == r->v[0]->index || l->v[2]->index == r->v[2]->index ||
+ l->v[0]->index == r->v[2]->index || l->v[0]->index == r->v[0]->index) {
+ return true;
+ }
+ }
+ if (l->v[1]->index == r->v[2]->index) {
+ if (l->v[2]->index == r->v[1]->index || l->v[2]->index == r->v[0]->index ||
+ l->v[0]->index == r->v[0]->index || l->v[0]->index == r->v[1]->index) {
+ return true;
+ }
+ }
+
+ /* Otherwise not possible. */
+ return false;
+}
+
+static LineartVert *lineart_triangle_share_point(const LineartTriangle *l,
+ const LineartTriangle *r)
+{
+ if (l->v[0] == r->v[0]) {
+ return r->v[0];
+ }
+ if (l->v[0] == r->v[1]) {
+ return r->v[1];
+ }
+ if (l->v[0] == r->v[2]) {
+ return r->v[2];
+ }
+ if (l->v[1] == r->v[0]) {
+ return r->v[0];
+ }
+ if (l->v[1] == r->v[1]) {
+ return r->v[1];
+ }
+ if (l->v[1] == r->v[2]) {
+ return r->v[2];
+ }
+ if (l->v[2] == r->v[0]) {
+ return r->v[0];
+ }
+ if (l->v[2] == r->v[1]) {
+ return r->v[1];
+ }
+ if (l->v[2] == r->v[2]) {
+ return r->v[2];
+ }
+ return NULL;
+}
+
+/* To save time and prevent overlapping lines when computing intersection lines. */
+static bool lineart_vert_already_intersected_2v(LineartVertIntersection *rv,
+ LineartVertIntersection *v1,
+ LineartVertIntersection *v2)
+{
+ return ((rv->isec1 == v1->base.index && rv->isec2 == v2->base.index) ||
+ (rv->isec2 == v2->base.index && rv->isec1 == v1->base.index));
+}
+
+static void lineart_vert_set_intersection_2v(LineartVert *rv, LineartVert *v1, LineartVert *v2)
+{
+ LineartVertIntersection *irv = (LineartVertIntersection *)rv;
+ irv->isec1 = v1->index;
+ irv->isec2 = v2->index;
+}
+
+/* This tests a triangle against a virtual line represented by v1---v2. The vertices returned after
+ * repeated calls to this function is then used to create a triangle/triangle intersection line. */
+static LineartVert *lineart_triangle_2v_intersection_test(LineartRenderBuffer *rb,
+ LineartVert *v1,
+ LineartVert *v2,
+ LineartTriangle *rt,
+ LineartTriangle *testing,
+ LineartVert *last)
+{
+ double Lv[3];
+ double Rv[3];
+ double dot_l, dot_r;
+ LineartVert *result;
+ double gloc[3];
+ LineartVert *l = v1, *r = v2;
+
+ for (LinkNode *ln = (void *)testing->intersecting_verts; ln; ln = ln->next) {
+ LineartVertIntersection *rv = ln->link;
+ if (rv->intersecting_with == rt &&
+ lineart_vert_already_intersected_2v(
+ rv, (LineartVertIntersection *)l, (LineartVertIntersection *)r)) {
+ return (LineartVert *)rv;
+ }
+ }
+
+ sub_v3_v3v3_db(Lv, l->gloc, testing->v[0]->gloc);
+ sub_v3_v3v3_db(Rv, r->gloc, testing->v[0]->gloc);
+
+ dot_l = dot_v3v3_db(Lv, testing->gn);
+ dot_r = dot_v3v3_db(Rv, testing->gn);
+
+ if (dot_l * dot_r > 0 || (!dot_l && !dot_r)) {
+ return 0;
+ }
+
+ dot_l = fabs(dot_l);
+ dot_r = fabs(dot_r);
+
+ interp_v3_v3v3_db(gloc, l->gloc, r->gloc, dot_l / (dot_l + dot_r));
+
+ /* Due to precision issue, we might end up with the same point as the one we already detected. */
+ if (last && LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[0], gloc[0]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[1], gloc[1]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[2], gloc[2])) {
+ return NULL;
+ }
+
+ if (!(lineart_point_inside_triangle3d(
+ gloc, testing->v[0]->gloc, testing->v[1]->gloc, testing->v[2]->gloc))) {
+ return NULL;
+ }
+
+ /* This is an intersection vert, the size is bigger than LineartVert,
+ * allocated separately. */
+ result = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartVertIntersection));
+
+ /* Indicate the data structure difference. */
+ result->flag = LRT_VERT_HAS_INTERSECTION_DATA;
+
+ copy_v3_v3_db(result->gloc, gloc);
+
+ lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, result);
+
+ return result;
+}
+
+/* Test if two triangles intersect. Generates one intersection line if the check succeeds */
+static LineartLine *lineart_triangle_intersect(LineartRenderBuffer *rb,
+ LineartTriangle *rt,
+ LineartTriangle *testing)
+{
+ LineartVert *l = 0, *r = 0;
+ LineartVert **next = &l;
+ LineartLine *result;
+ LineartVert *E0T = 0;
+ LineartVert *E1T = 0;
+ LineartVert *E2T = 0;
+ LineartVert *TE0 = 0;
+ LineartVert *TE1 = 0;
+ LineartVert *TE2 = 0;
+ LineartVert *sv1, *sv2;
+ double cl[3];
+
+ double ZMin, ZMax;
+ ZMax = rb->far_clip;
+ ZMin = rb->near_clip;
+ copy_v3_v3_db(cl, rb->camera_pos);
+ LineartVert *share = lineart_triangle_share_point(testing, rt);
+
+ if (share) {
+ /* If triangles have sharing points like (abc) and (acd), then we only need to detect bc
+ * against acd or cd against abc.*/
+
+ LineartVert *new_share;
+ lineart_triangle_get_other_verts(rt, share, &sv1, &sv2);
+
+ l = new_share = lineart_mem_aquire(&rb->render_data_pool, (sizeof(LineartVertIntersection)));
+
+ new_share->flag = LRT_VERT_HAS_INTERSECTION_DATA;
+
+ copy_v3_v3_db(new_share->gloc, share->gloc);
+
+ r = lineart_triangle_2v_intersection_test(rb, sv1, sv2, rt, testing, 0);
+
+ if (r == NULL) {
+ lineart_triangle_get_other_verts(testing, share, &sv1, &sv2);
+ r = lineart_triangle_2v_intersection_test(rb, sv1, sv2, testing, rt, 0);
+ if (r == NULL) {
+ return 0;
+ }
+ lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, new_share);
+ }
+ else {
+ lineart_prepend_pool(&rt->intersecting_verts, &rb->render_data_pool, new_share);
+ }
+ }
+ else {
+ /* If not sharing any points, then we need to try all the possibilities. */
+
+ E0T = lineart_triangle_2v_intersection_test(rb, rt->v[0], rt->v[1], rt, testing, 0);
+ if (E0T && (!(*next))) {
+ (*next) = E0T;
+ lineart_vert_set_intersection_2v((*next), rt->v[0], rt->v[1]);
+ next = &r;
+ }
+ E1T = lineart_triangle_2v_intersection_test(rb, rt->v[1], rt->v[2], rt, testing, l);
+ if (E1T && (!(*next))) {
+ (*next) = E1T;
+ lineart_vert_set_intersection_2v((*next), rt->v[1], rt->v[2]);
+ next = &r;
+ }
+ if (!(*next)) {
+ E2T = lineart_triangle_2v_intersection_test(rb, rt->v[2], rt->v[0], rt, testing, l);
+ }
+ if (E2T && (!(*next))) {
+ (*next) = E2T;
+ lineart_vert_set_intersection_2v((*next), rt->v[2], rt->v[0]);
+ next = &r;
+ }
+
+ if (!(*next)) {
+ TE0 = lineart_triangle_2v_intersection_test(
+ rb, testing->v[0], testing->v[1], testing, rt, l);
+ }
+ if (TE0 && (!(*next))) {
+ (*next) = TE0;
+ lineart_vert_set_intersection_2v((*next), testing->v[0], testing->v[1]);
+ next = &r;
+ }
+ if (!(*next)) {
+ TE1 = lineart_triangle_2v_intersection_test(
+ rb, testing->v[1], testing->v[2], testing, rt, l);
+ }
+ if (TE1 && (!(*next))) {
+ (*next) = TE1;
+ lineart_vert_set_intersection_2v((*next), testing->v[1], testing->v[2]);
+ next = &r;
+ }
+ if (!(*next)) {
+ TE2 = lineart_triangle_2v_intersection_test(
+ rb, testing->v[2], testing->v[0], testing, rt, l);
+ }
+ if (TE2 && (!(*next))) {
+ (*next) = TE2;
+ lineart_vert_set_intersection_2v((*next), testing->v[2], testing->v[0]);
+ next = &r;
+ }
+
+ if (!(*next)) {
+ return 0;
+ }
+ }
+
+ /* The intersection line has been generated only in geometry space, so we need to transform them
+ * as well. */
+ mul_v4_m4v3_db(l->fbcoord, rb->view_projection, l->gloc);
+ mul_v4_m4v3_db(r->fbcoord, rb->view_projection, r->gloc);
+ mul_v3db_db(l->fbcoord, (1 / l->fbcoord[3]));
+ mul_v3db_db(r->fbcoord, (1 / r->fbcoord[3]));
+
+ l->fbcoord[0] -= rb->shift_x * 2;
+ l->fbcoord[1] -= rb->shift_y * 2;
+ r->fbcoord[0] -= rb->shift_x * 2;
+ r->fbcoord[1] -= rb->shift_y * 2;
+
+ /* This z transformation is not the same as the rest of the part, because the data don't go
+ * through normal perspective division calls in the pipeline, but this way the 3D result and
+ * occlution on the generated line is correct, and we don't really use 2D for viewport stroke
+ * generation anyway.*/
+ l->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(l->fbcoord[2]) * (ZMax - ZMin));
+ r->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(r->fbcoord[2]) * (ZMax - ZMin));
+
+ ((LineartVertIntersection *)l)->intersecting_with = rt;
+ ((LineartVertIntersection *)r)->intersecting_with = testing;
+
+ result = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLine));
+ result->l = l;
+ result->r = r;
+ result->tl = rt;
+ result->tr = testing;
+
+ LineartLineSegment *rls = lineart_mem_aquire(&rb->render_data_pool, sizeof(LineartLineSegment));
+ BLI_addtail(&result->segments, rls);
+ /* Don't need to OR flags right now, just a type mark. */
+ result->flags = LRT_EDGE_FLAG_INTERSECTION;
+ lineart_prepend_line_direct(&rb->intersection_lines, result);
+ int r1, r2, c1, c2, row, col;
+ if (lineart_get_line_bounding_areas(rb, result, &r1, &r2, &c1, &c2)) {
+ for (row = r1; row != r2 + 1; row++) {
+ for (col = c1; col != c2 + 1; col++) {
+ lineart_bounding_area_link_line(
+ rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], result);
+ }
+ }
+ }
+
+ rb->intersection_count++;
+
+ return result;
+}
+
+static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
+ LineartTriangle *rt,
+ LineartBoundingArea *ba)
+{
+ /* Testing_triangle->testing[0] is used to store pairing triangle reference.
+ * See definition of LineartTriangleThread for more info. */
+ LineartTriangle *testing_triangle;
+ LineartTriangleThread *rtt;
+ LinkData *lip, *next_lip;
+
+ double *G0 = rt->v[0]->gloc, *G1 = rt->v[1]->gloc, *G2 = rt->v[2]->gloc;
+
+ /* If this is not the smallest subdiv bounding area.*/
+ if (ba->child) {
+ lineart_triangle_intersect_in_bounding_area(rb, rt, &ba->child[0]);
+ lineart_triangle_intersect_in_bounding_area(rb, rt, &ba->child[1]);
+ lineart_triangle_intersect_in_bounding_area(rb, rt, &ba->child[2]);
+ lineart_triangle_intersect_in_bounding_area(rb, rt, &ba->child[3]);
+ return;
+ }
+
+ /* If this _is_ the smallest subdiv bounding area, then do the intersections there. */
+ for (lip = ba->linked_triangles.first; lip; lip = next_lip) {
+ next_lip = lip->next;
+ testing_triangle = lip->data;
+ rtt = (LineartTriangleThread *)testing_triangle;
+
+ if (testing_triangle == rt || rtt->testing[0] == (LineartLine *)rt ||
+ (testing_triangle->flags & LRT_TRIANGLE_NO_INTERSECTION) ||
+ ((testing_triangle->flags & LRT_TRIANGLE_INTERSECTION_ONLY) &&
+ (rt->flags & LRT_TRIANGLE_INTERSECTION_ONLY)) ||
+ lineart_triangle_share_edge(rt, testing_triangle)) {
+ continue;
+ }
+
+ rtt->testing[0] = (LineartLine *)rt;
+ double *RG0 = testing_triangle->v[0]->gloc, *RG1 = testing_triangle->v[1]->gloc,
+ *RG2 = testing_triangle->v[2]->gloc;
+
+ /* Bounding box not overlapping, not potential of intersecting. */
+ if ((MIN3(G0[2], G1[2], G2[2]) > MAX3(RG0[2], RG1[2], RG2[2])) ||
+ (MAX3(G0[2], G1[2], G2[2]) < MIN3(RG0[2], RG1[2], RG2[2])) ||
+ (MIN3(G0[0], G1[0], G2[0]) > MAX3(RG0[0], RG1[0], RG2[0])) ||
+ (MAX3(G0[0], G1[0], G2[0]) < MIN3(RG0[0], RG1[0], RG2[0])) ||
+ (MIN3(G0[1], G1[1], G2[1]) > MAX3(RG0[1], RG1[1], RG2[1])) ||
+ (MAX3(G0[1], G1[1], G2[1]) < MIN3(RG0[1], RG1[1], RG2[1]))) {
+ continue;
+ }
+
+ /* If we do need to compute intersection, then finally do it. */
+ lineart_triangle_intersect(rb, rt, testing_triangle);
+ }
+}
+
+/* The calculated view vector will point towards the far-plane from the camera position. */
+static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
+{
+ float direction[3] = {0, 0, 1};
+ float trans[3];
+ float inv[4][4];
+ float obmat_no_scale[4][4];
+
+ copy_m4_m4(obmat_no_scale, rb->cam_obmat);
+
+ normalize_v3(obmat_no_scale[0]);
+ normalize_v3(obmat_no_scale[1]);
+ normalize_v3(obmat_no_scale[2]);
+ invert_m4_m4(inv, obmat_no_scale);
+ transpose_m4(inv);
+ mul_v3_mat3_m4v3(trans, inv, direction);
+ copy_m4_m4(rb->cam_obmat, obmat_no_scale);
+ copy_v3db_v3fl(rb->view_vector, trans);
+}
+
+static void lineart_destroy_render_data(LineartRenderBuffer *rb)
+{
+ if (rb == NULL) {
+ return;
+ }
+
+ rb->contour_count = 0;
+ rb->contour_managed = NULL;
+ rb->intersection_count = 0;
+ rb->intersection_managed = NULL;
+ rb->material_line_count = 0;
+ rb->material_managed = NULL;
+ rb->crease_count = 0;
+ rb->crease_managed = NULL;
+ rb->edge_mark_count = 0;
+ rb->edge_mark_managed = NULL;
+
+ rb->contours = NULL;
+ rb->intersection_lines = NULL;
+ rb->crease_lines = NULL;
+ rb->material_lines = NULL;
+ rb->edge_marks = NULL;
+
+ BLI_listbase_clear(&rb->chains);
+ BLI_listbase_clear(&rb->wasted_cuts);
+
+ BLI_listbase_clear(&rb->vertex_buffer_pointers);
+ BLI_listbase_clear(&rb->line_buffer_pointers);
+ BLI_listbase_clear(&rb->triangle_buffer_pointers);
+
+ BLI_spin_end(&rb->lock_task);
+ BLI_spin_end(&rb->lock_cuts);
+ BLI_spin_end(&rb->render_data_pool.lock_mem);
+
+ lineart_mem_destroy(&rb->render_data_pool);
+}
+
+void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
+{
+ LineartRenderBuffer *rb = lmd->render_buffer;
+
+ lineart_destroy_render_data(rb);
+
+ if (rb) {
+ MEM_freeN(rb);
+ lmd->render_buffer = NULL;
+ }
+
+ if (G.debug_value == 4000) {
+ printf("LRT: Destroyed render data.\n");
+ }
+}
+
+static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
+ LineartGpencilModifierData *lmd)
+{
+ LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
+
+ lmd->render_buffer = rb;
+
+ if (!scene || !scene->camera) {
+ return NULL;
+ }
+ Camera *c = scene->camera->data;
+ double clipping_offset = 0;
+
+ if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) {
+ /* This way the clipped lines are "stablely visible" by prevents depth buffer artefacts. */
+ clipping_offset = 0.0001;
+ }
+
+ copy_v3db_v3fl(rb->camera_pos, scene->camera->obmat[3]);
+ copy_m4_m4(rb->cam_obmat, scene->camera->obmat);
+ rb->cam_is_persp = (c->type == CAM_PERSP);
+ rb->near_clip = c->clip_start + clipping_offset;
+ rb->far_clip = c->clip_end - clipping_offset;
+ rb->w = scene->r.xsch;
+ rb->h = scene->r.ysch;
+
+ double asp = ((double)rb->w / (double)rb->h);
+ rb->shift_x = (asp >= 1) ? c->shiftx : c->shiftx * asp;
+ rb->shift_y = (asp <= 1) ? c->shifty : c->shifty * asp;
+
+ rb->crease_threshold = cos(M_PI - lmd->crease_threshold);
+ rb->angle_splitting_threshold = lmd->angle_splitting_threshold;
+ rb->chaining_image_threshold = lmd->chaining_image_threshold;
+ rb->chaining_geometry_threshold = lmd->chaining_geometry_threshold;
+
+ rb->fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
+ rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
+ rb->allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
+ rb->remove_doubles = (lmd->calculation_flags & LRT_REMOVE_DOUBLES) != 0;
+
+ /* See lineart_edge_from_triangle() for how this option may impact performance. */
+ rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
+
+ rb->use_contour = (lmd->line_types & LRT_EDGE_FLAG_CONTOUR) != 0;
+ rb->use_crease = (lmd->line_types & LRT_EDGE_FLAG_CREASE) != 0;
+ rb->use_material = (lmd->line_types & LRT_EDGE_FLAG_MATERIAL) != 0;
+ rb->use_edge_marks = (lmd->line_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
+ rb->use_intersections = (lmd->line_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
+
+ BLI_spin_init(&rb->lock_task);
+ BLI_spin_init(&rb->lock_cuts);
+ BLI_spin_init(&rb->render_data_pool.lock_mem);
+
+ return rb;
+}
+
+static int lineart_triangle_size_get(const Scene *scene, LineartRenderBuffer *rb)
+{
+ if (rb->thread_count == 0) {
+ rb->thread_count = BKE_render_num_threads(&scene->r);
+ }
+ return sizeof(LineartTriangle) + (sizeof(LineartLine *) * (rb->thread_count));
+}
+
+static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
+{
+ /* Initial tile split is defined as 4 (subdivided as 4*4), increasing the value allows the
+ * algorithm to build the acceleration structure for bigger scenes a little faster but not as
+ * efficient at handling medium to small scenes. */
+ int sp_w = LRT_BA_ROWS;
+ int sp_h = LRT_BA_ROWS;
+ int row, col;
+ LineartBoundingArea *ba;
+
+ /* Because NDC (Normalized Device Coordinates) range is (-1,1),
+ * so the span for each initial tile is double of that in the (0,1) range. */
+ double span_w = (double)1 / sp_w * 2.0;
+ double span_h = (double)1 / sp_h * 2.0;
+
+ rb->tile_count_x = sp_w;
+ rb->tile_count_y = sp_h;
+ rb->width_per_tile = span_w;
+ rb->height_per_tile = span_h;
+
+ rb->bounding_area_count = sp_w * sp_h;
+ rb->initial_bounding_areas = lineart_mem_aquire(
+ &rb->render_data_pool, sizeof(LineartBoundingArea) * rb->bounding_area_count);
+
+ /* Initialize tiles. */
+ for (row = 0; row < sp_h; row++) {
+ for (col = 0; col < sp_w; col++) {
+ ba = &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+
+ /* Set the four direction limits. */
+ ba->l = span_w * col - 1.0;
+ ba->r = (col == sp_w - 1) ? 1.0 : (span_w * (col + 1) - 1.0);
+ ba->u = 1.0 - span_h * row;
+ ba->b = (row == sp_h - 1) ? -1.0 : (1.0 - span_h * (row + 1));
+
+ ba->cx = (ba->l + ba->r) / 2;
+ ba->cy = (ba->u + ba->b) / 2;
+
+ /* Link adjacent ones. */
+ if (row) {
+ lineart_list_append_pointer_pool(
+ &ba->up,
+ &rb->render_data_pool,
+ &rb->initial_bounding_areas[(row - 1) * LRT_BA_ROWS + col]);
+ }
+ if (col) {
+ lineart_list_append_pointer_pool(&ba->lp,
+ &rb->render_data_pool,
+ &rb->initial_bounding_areas[row * LRT_BA_ROWS + col - 1]);
+ }
+ if (row != sp_h - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->bp,
+ &rb->render_data_pool,
+ &rb->initial_bounding_areas[(row + 1) * LRT_BA_ROWS + col]);
+ }
+ if (col != sp_w - 1) {
+ lineart_list_append_pointer_pool(&ba->rp,
+ &rb->render_data_pool,
+ &rb->initial_bounding_areas[row * LRT_BA_ROWS + col + 1]);
+ }
+ }
+ }
+}
+
+/* Re-link adjacent tiles after one gets subdivided. */
+static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartBoundingArea *root)
+{
+ LineartBoundingArea *ba = root->child, *tba;
+ LinkData *lip2, *next_lip;
+ LineartStaticMemPool *mph = &rb->render_data_pool;
+
+ /* Inter-connection with newly created 4 child bounding areas. */
+ lineart_list_append_pointer_pool(&ba[1].rp, mph, &ba[0]);
+ lineart_list_append_pointer_pool(&ba[0].lp, mph, &ba[1]);
+ lineart_list_append_pointer_pool(&ba[1].bp, mph, &ba[2]);
+ lineart_list_append_pointer_pool(&ba[2].up, mph, &ba[1]);
+ lineart_list_append_pointer_pool(&ba[2].rp, mph, &ba[3]);
+ lineart_list_append_pointer_pool(&ba[3].lp, mph, &ba[2]);
+ lineart_list_append_pointer_pool(&ba[3].up, mph, &ba[0]);
+ lineart_list_append_pointer_pool(&ba[0].bp, mph, &ba[3]);
+
+ /* Connect 4 child bounding areas to other areas that are
+ * adjacent to their original parents. */
+ LISTBASE_FOREACH (LinkData *, lip, &root->lp) {
+
+ /* For example, we are dealing with parent's left side
+ * "tba" represents each adjacent neighbor of the parent. */
+ tba = lip->data;
+
+ /* if this neighbor is adjacent to
+ * the two new areas on the left side of the parent,
+ * then add them to the adjacent list as well. */
+ if (ba[1].u > tba->b && ba[1].b < tba->u) {
+ lineart_list_append_pointer_pool(&ba[1].lp, mph, tba);
+ lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]);
+ }
+ if (ba[2].u > tba->b && ba[2].b < tba->u) {
+ lineart_list_append_pointer_pool(&ba[2].lp, mph, tba);
+ lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]);
+ }
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &root->rp) {
+ tba = lip->data;
+ if (ba[0].u > tba->b && ba[0].b < tba->u) {
+ lineart_list_append_pointer_pool(&ba[0].rp, mph, tba);
+ lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]);
+ }
+ if (ba[3].u > tba->b && ba[3].b < tba->u) {
+ lineart_list_append_pointer_pool(&ba[3].rp, mph, tba);
+ lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]);
+ }
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &root->up) {
+ tba = lip->data;
+ if (ba[0].r > tba->l && ba[0].l < tba->r) {
+ lineart_list_append_pointer_pool(&ba[0].up, mph, tba);
+ lineart_list_append_pointer_pool(&tba->bp, mph, &ba[0]);
+ }
+ if (ba[1].r > tba->l && ba[1].l < tba->r) {
+ lineart_list_append_pointer_pool(&ba[1].up, mph, tba);
+ lineart_list_append_pointer_pool(&tba->bp, mph, &ba[1]);
+ }
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &root->bp) {
+ tba = lip->data;
+ if (ba[2].r > tba->l && ba[2].l < tba->r) {
+ lineart_list_append_pointer_pool(&ba[2].bp, mph, tba);
+ lineart_list_append_pointer_pool(&tba->up, mph, &ba[2]);
+ }
+ if (ba[3].r > tba->l && ba[3].l < tba->r) {
+ lineart_list_append_pointer_pool(&ba[3].bp, mph, tba);
+ lineart_list_append_pointer_pool(&tba->up, mph, &ba[3]);
+ }
+ }
+
+ /* Then remove the parent bounding areas from
+ * their original adjacent areas. */
+ LISTBASE_FOREACH (LinkData *, lip, &root->lp) {
+ for (lip2 = ((LineartBoundingArea *)lip->data)->rp.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == root) {
+ lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->rp, lip2);
+ if (ba[1].u > tba->b && ba[1].b < tba->u) {
+ lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]);
+ }
+ if (ba[2].u > tba->b && ba[2].b < tba->u) {
+ lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]);
+ }
+ }
+ }
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &root->rp) {
+ for (lip2 = ((LineartBoundingArea *)lip->data)->lp.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == root) {
+ lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->lp, lip2);
+ if (ba[0].u > tba->b && ba[0].b < tba->u) {
+ lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]);
+ }
+ if (ba[3].u > tba->b && ba[3].b < tba->u) {
+ lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]);
+ }
+ }
+ }
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &root->up) {
+ for (lip2 = ((LineartBoundingArea *)lip->data)->bp.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == root) {
+ lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->bp, lip2);
+ if (ba[0].r > tba->l && ba[0].l < tba->r) {
+ lineart_list_append_pointer_pool(&tba->up, mph, &ba[0]);
+ }
+ if (ba[1].r > tba->l && ba[1].l < tba->r) {
+ lineart_list_append_pointer_pool(&tba->up, mph, &ba[1]);
+ }
+ }
+ }
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &root->bp) {
+ for (lip2 = ((LineartBoundingArea *)lip->data)->up.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == root) {
+ lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->up, lip2);
+ if (ba[2].r > tba->l && ba[2].l < tba->r) {
+ lineart_list_append_pointer_pool(&tba->bp, mph, &ba[2]);
+ }
+ if (ba[3].r > tba->l && ba[3].l < tba->r) {
+ lineart_list_append_pointer_pool(&tba->bp, mph, &ba[3]);
+ }
+ }
+ }
+ }
+
+ /* Finally clear parent'scene adjacent list. */
+ BLI_listbase_clear(&root->lp);
+ BLI_listbase_clear(&root->rp);
+ BLI_listbase_clear(&root->up);
+ BLI_listbase_clear(&root->bp);
+}
+
+/* Subdivide a tile after one tile contains too many triangles. */
+static void lineart_bounding_area_split(LineartRenderBuffer *rb,
+ LineartBoundingArea *root,
+ int recursive_level)
+{
+ LineartBoundingArea *ba = lineart_mem_aquire(&rb->render_data_pool,
+ sizeof(LineartBoundingArea) * 4);
+ LineartTriangle *rt;
+ LineartLine *rl;
+
+ ba[0].l = root->cx;
+ ba[0].r = root->r;
+ ba[0].u = root->u;
+ ba[0].b = root->cy;
+ ba[0].cx = (ba[0].l + ba[0].r) / 2;
+ ba[0].cy = (ba[0].u + ba[0].b) / 2;
+
+ ba[1].l = root->l;
+ ba[1].r = root->cx;
+ ba[1].u = root->u;
+ ba[1].b = root->cy;
+ ba[1].cx = (ba[1].l + ba[1].r) / 2;
+ ba[1].cy = (ba[1].u + ba[1].b) / 2;
+
+ ba[2].l = root->l;
+ ba[2].r = root->cx;
+ ba[2].u = root->cy;
+ ba[2].b = root->b;
+ ba[2].cx = (ba[2].l + ba[2].r) / 2;
+ ba[2].cy = (ba[2].u + ba[2].b) / 2;
+
+ ba[3].l = root->cx;
+ ba[3].r = root->r;
+ ba[3].u = root->cy;
+ ba[3].b = root->b;
+ ba[3].cx = (ba[3].l + ba[3].r) / 2;
+ ba[3].cy = (ba[3].u + ba[3].b) / 2;
+
+ root->child = ba;
+
+ lineart_bounding_areas_connect_new(rb, root);
+
+ while ((rt = lineart_list_pop_pointer_no_free(&root->linked_triangles)) != NULL) {
+ LineartBoundingArea *cba = root->child;
+ double b[4];
+ b[0] = MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[1] = MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[2] = MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ b[3] = MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ if (LRT_BOUND_AREA_CROSSES(b, &cba[0].l)) {
+ lineart_bounding_area_link_triangle(rb, &cba[0], rt, b, 0, recursive_level + 1, false);
+ }
+ if (LRT_BOUND_AREA_CROSSES(b, &cba[1].l)) {
+ lineart_bounding_area_link_triangle(rb, &cba[1], rt, b, 0, recursive_level + 1, false);
+ }
+ if (LRT_BOUND_AREA_CROSSES(b, &cba[2].l)) {
+ lineart_bounding_area_link_triangle(rb, &cba[2], rt, b, 0, recursive_level + 1, false);
+ }
+ if (LRT_BOUND_AREA_CROSSES(b, &cba[3].l)) {
+ lineart_bounding_area_link_triangle(rb, &cba[3], rt, b, 0, recursive_level + 1, false);
+ }
+ }
+
+ while ((rl = lineart_list_pop_pointer_no_free(&root->linked_lines)) != NULL) {
+ lineart_bounding_area_link_line(rb, root, rl);
+ }
+
+ rb->bounding_area_count += 3;
+}
+
+static bool lineart_bounding_area_line_intersect(LineartRenderBuffer *UNUSED(fb),
+ const double l[2],
+ const double r[2],
+ LineartBoundingArea *ba)
+{
+ double vx, vy;
+ double converted[4];
+ double c1, c;
+
+ if (((converted[0] = (double)ba->l) > MAX2(l[0], r[0])) ||
+ ((converted[1] = (double)ba->r) < MIN2(l[0], r[0])) ||
+ ((converted[2] = (double)ba->b) > MAX2(l[1], r[1])) ||
+ ((converted[3] = (double)ba->u) < MIN2(l[1], r[1]))) {
+ return false;
+ }
+
+ vx = l[0] - r[0];
+ vy = l[1] - r[1];
+
+ c1 = vx * (converted[2] - l[1]) - vy * (converted[0] - l[0]);
+ c = c1;
+
+ c1 = vx * (converted[2] - l[1]) - vy * (converted[1] - l[0]);
+ if (c1 * c <= 0) {
+ return true;
+ }
+ c = c1;
+
+ c1 = vx * (converted[3] - l[1]) - vy * (converted[0] - l[0]);
+ if (c1 * c <= 0) {
+ return true;
+ }
+ c = c1;
+
+ c1 = vx * (converted[3] - l[1]) - vy * (converted[1] - l[0]);
+ if (c1 * c <= 0) {
+ return true;
+ }
+ c = c1;
+
+ return false;
+}
+
+static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
+ LineartTriangle *rt,
+ LineartBoundingArea *ba)
+{
+ double p1[2], p2[2], p3[2], p4[2];
+ double *FBC1 = rt->v[0]->fbcoord, *FBC2 = rt->v[1]->fbcoord, *FBC3 = rt->v[2]->fbcoord;
+
+ p3[0] = p1[0] = (double)ba->l;
+ p2[1] = p1[1] = (double)ba->b;
+ p2[0] = p4[0] = (double)ba->r;
+ p3[1] = p4[1] = (double)ba->u;
+
+ if ((FBC1[0] >= p1[0] && FBC1[0] <= p2[0] && FBC1[1] >= p1[1] && FBC1[1] <= p3[1]) ||
+ (FBC2[0] >= p1[0] && FBC2[0] <= p2[0] && FBC2[1] >= p1[1] && FBC2[1] <= p3[1]) ||
+ (FBC3[0] >= p1[0] && FBC3[0] <= p2[0] && FBC3[1] >= p1[1] && FBC3[1] <= p3[1])) {
+ return true;
+ }
+
+ if (lineart_point_inside_triangle(p1, FBC1, FBC2, FBC3) ||
+ lineart_point_inside_triangle(p2, FBC1, FBC2, FBC3) ||
+ lineart_point_inside_triangle(p3, FBC1, FBC2, FBC3) ||
+ lineart_point_inside_triangle(p4, FBC1, FBC2, FBC3)) {
+ return true;
+ }
+
+ if ((lineart_bounding_area_line_intersect(fb, FBC1, FBC2, ba)) ||
+ (lineart_bounding_area_line_intersect(fb, FBC2, FBC3, ba)) ||
+ (lineart_bounding_area_line_intersect(fb, FBC3, FBC1, ba))) {
+ return true;
+ }
+
+ return false;
+}
+
+/* 1) Link triangles with bounding areas for later occlusion test.
+ * 2) Test triangles with existing(added previously) triangles for intersection lines. */
+static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
+ LineartBoundingArea *root_ba,
+ LineartTriangle *rt,
+ double *LRUB,
+ int recursive,
+ int recursive_level,
+ bool do_intersection)
+{
+ if (!lineart_bounding_area_triangle_intersect(rb, rt, root_ba)) {
+ return;
+ }
+ if (root_ba->child == NULL) {
+ lineart_list_append_pointer_pool(&root_ba->linked_triangles, &rb->render_data_pool, rt);
+ root_ba->triangle_count++;
+ /* If splitting doesn't improve triangle separation, then shouldn't allow splitting anymore.
+ * Here we use recursive limit. This is espetially useful in ortho render, where a lot of
+ * faces could easily line up perfectly in image space, which can not be separated by simply
+ * slicing the image tile. */
+ if (root_ba->triangle_count > 200 && recursive && recursive_level < 10) {
+ lineart_bounding_area_split(rb, root_ba, recursive_level);
+ }
+ if (recursive && do_intersection && rb->use_intersections) {
+ lineart_triangle_intersect_in_bounding_area(rb, rt, root_ba);
+ }
+ }
+ else {
+ LineartBoundingArea *ba = root_ba->child;
+ double *B1 = LRUB;
+ double b[4];
+ if (!LRUB) {
+ b[0] = MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[1] = MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[2] = MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ b[3] = MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ B1 = b;
+ }
+ if (LRT_BOUND_AREA_CROSSES(B1, &ba[0].l)) {
+ lineart_bounding_area_link_triangle(
+ rb, &ba[0], rt, B1, recursive, recursive_level + 1, do_intersection);
+ }
+ if (LRT_BOUND_AREA_CROSSES(B1, &ba[1].l)) {
+ lineart_bounding_area_link_triangle(
+ rb, &ba[1], rt, B1, recursive, recursive_level + 1, do_intersection);
+ }
+ if (LRT_BOUND_AREA_CROSSES(B1, &ba[2].l)) {
+ lineart_bounding_area_link_triangle(
+ rb, &ba[2], rt, B1, recursive, recursive_level + 1, do_intersection);
+ }
+ if (LRT_BOUND_AREA_CROSSES(B1, &ba[3].l)) {
+ lineart_bounding_area_link_triangle(
+ rb, &ba[3], rt, B1, recursive, recursive_level + 1, do_intersection);
+ }
+ }
+}
+
+static void lineart_bounding_area_link_line(LineartRenderBuffer *rb,
+ LineartBoundingArea *root_ba,
+ LineartLine *rl)
+{
+ if (root_ba->child == NULL) {
+ lineart_list_append_pointer_pool(&root_ba->linked_lines, &rb->render_data_pool, rl);
+ }
+ else {
+ if (lineart_bounding_area_line_intersect(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &root_ba->child[0])) {
+ lineart_bounding_area_link_line(rb, &root_ba->child[0], rl);
+ }
+ if (lineart_bounding_area_line_intersect(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &root_ba->child[1])) {
+ lineart_bounding_area_link_line(rb, &root_ba->child[1], rl);
+ }
+ if (lineart_bounding_area_line_intersect(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &root_ba->child[2])) {
+ lineart_bounding_area_link_line(rb, &root_ba->child[2], rl);
+ }
+ if (lineart_bounding_area_line_intersect(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &root_ba->child[3])) {
+ lineart_bounding_area_link_line(rb, &root_ba->child[3], rl);
+ }
+ }
+}
+
+/* Link lines to their respective bounding areas. */
+static void lineart_main_link_lines(LineartRenderBuffer *rb)
+{
+ LRT_ITER_ALL_LINES_BEGIN
+ {
+ int r1, r2, c1, c2, row, col;
+ if (lineart_get_line_bounding_areas(rb, rl, &r1, &r2, &c1, &c2)) {
+ for (row = r1; row != r2 + 1; row++) {
+ for (col = c1; col != c2 + 1; col++) {
+ lineart_bounding_area_link_line(
+ rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], rl);
+ }
+ }
+ }
+ }
+ LRT_ITER_ALL_LINES_END
+}
+
+static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
+ LineartTriangle *rt,
+ int *rowbegin,
+ int *rowend,
+ int *colbegin,
+ int *colend)
+{
+ double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double b[4];
+
+ if (!rt->v[0] || !rt->v[1] || !rt->v[2]) {
+ return false;
+ }
+
+ b[0] = MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[1] = MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[2] = MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ b[3] = MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+
+ if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) {
+ return false;
+ }
+
+ (*colbegin) = (int)((b[0] + 1.0) / sp_w);
+ (*colend) = (int)((b[1] + 1.0) / sp_w);
+ (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+
+ if ((*colend) >= rb->tile_count_x) {
+ (*colend) = rb->tile_count_x - 1;
+ }
+ if ((*rowend) >= rb->tile_count_y) {
+ (*rowend) = rb->tile_count_y - 1;
+ }
+ if ((*colbegin) < 0) {
+ (*colbegin) = 0;
+ }
+ if ((*rowbegin) < 0) {
+ (*rowbegin) = 0;
+ }
+
+ return true;
+}
+
+static bool lineart_get_line_bounding_areas(LineartRenderBuffer *rb,
+ LineartLine *rl,
+ int *rowbegin,
+ int *rowend,
+ int *colbegin,
+ int *colend)
+{
+ double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double b[4];
+
+ if (!rl->l || !rl->r) {
+ return false;
+ }
+
+ if (rl->l->fbcoord[0] != rl->l->fbcoord[0] || rl->r->fbcoord[0] != rl->r->fbcoord[0]) {
+ return false;
+ }
+
+ b[0] = MIN2(rl->l->fbcoord[0], rl->r->fbcoord[0]);
+ b[1] = MAX2(rl->l->fbcoord[0], rl->r->fbcoord[0]);
+ b[2] = MIN2(rl->l->fbcoord[1], rl->r->fbcoord[1]);
+ b[3] = MAX2(rl->l->fbcoord[1], rl->r->fbcoord[1]);
+
+ if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) {
+ return false;
+ }
+
+ (*colbegin) = (int)((b[0] + 1.0) / sp_w);
+ (*colend) = (int)((b[1] + 1.0) / sp_w);
+ (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+
+ /* It'scene possible that the line stretches too much out to the side, resulting negative value
+ . */
+ if ((*rowend) < (*rowbegin)) {
+ (*rowend) = rb->tile_count_y - 1;
+ }
+
+ if ((*colend) < (*colbegin)) {
+ (*colend) = rb->tile_count_x - 1;
+ }
+
+ CLAMP((*colbegin), 0, rb->tile_count_x - 1);
+ CLAMP((*rowbegin), 0, rb->tile_count_y - 1);
+ CLAMP((*colend), 0, rb->tile_count_x - 1);
+ CLAMP((*rowend), 0, rb->tile_count_y - 1);
+
+ return true;
+}
+
+/* This only gets initial "biggest" tile. */
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
+ double x,
+ double y)
+{
+ double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ int col, row;
+
+ if (x > 1 || x < -1 || y > 1 || y < -1) {
+ return 0;
+ }
+
+ col = (int)((x + 1.0) / sp_w);
+ row = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+
+ if (col >= rb->tile_count_x) {
+ col = rb->tile_count_x - 1;
+ }
+ if (row >= rb->tile_count_y) {
+ row = rb->tile_count_y - 1;
+ }
+ if (col < 0) {
+ col = 0;
+ }
+ if (row < 0) {
+ row = 0;
+ }
+
+ return &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+}
+
+static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+{
+ LineartBoundingArea *iba;
+ double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ int c = (int)((x + 1.0) / sp_w);
+ int r = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ if (r < 0) {
+ r = 0;
+ }
+ if (c < 0) {
+ c = 0;
+ }
+ if (r >= rb->tile_count_y) {
+ r = rb->tile_count_y - 1;
+ }
+ if (c >= rb->tile_count_x) {
+ c = rb->tile_count_x - 1;
+ }
+
+ iba = &rb->initial_bounding_areas[r * LRT_BA_ROWS + c];
+ while (iba->child) {
+ if (x > iba->cx) {
+ if (y > iba->cy) {
+ iba = &iba->child[0];
+ }
+ else {
+ iba = &iba->child[3];
+ }
+ }
+ else {
+ if (y > iba->cy) {
+ iba = &iba->child[1];
+ }
+ else {
+ iba = &iba->child[2];
+ }
+ }
+ }
+ return iba;
+}
+
+/* Wrapper for more convenience. */
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+{
+ LineartBoundingArea *ba;
+ if ((ba = MOD_lineart_get_parent_bounding_area(rb, x, y)) != NULL) {
+ return lineart_get_bounding_area(rb, x, y);
+ }
+ return NULL;
+}
+
+/* Sequentially add triangles into render buffer. This also does intersection along the way. */
+static void lineart_main_add_triangles(LineartRenderBuffer *rb)
+{
+ LineartTriangle *rt;
+ int i, lim;
+ int x1, x2, y1, y2;
+ int r, co;
+
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ rt = reln->pointer;
+ lim = reln->element_count;
+ for (i = 0; i < lim; i++) {
+ if ((rt->flags & LRT_CULL_USED) || (rt->flags & LRT_CULL_DISCARD)) {
+ rt = (void *)(((unsigned char *)rt) + rb->triangle_size);
+ continue;
+ }
+ if (lineart_get_triangle_bounding_areas(rb, rt, &y1, &y2, &x1, &x2)) {
+ for (co = x1; co <= x2; co++) {
+ for (r = y1; r <= y2; r++) {
+ lineart_bounding_area_link_triangle(rb,
+ &rb->initial_bounding_areas[r * LRT_BA_ROWS + co],
+ rt,
+ 0,
+ 1,
+ 0,
+ (!(rt->flags & LRT_TRIANGLE_NO_INTERSECTION)));
+ }
+ }
+ } /* Else throw away. */
+ rt = (void *)(((unsigned char *)rt) + rb->triangle_size);
+ }
+ }
+}
+
+/* This function gets the tile for the point rl->l, and later use lineart_bounding_area_next() to
+ * get next along the way. */
+static LineartBoundingArea *lineart_line_first_bounding_area(LineartRenderBuffer *rb,
+ LineartLine *rl)
+{
+ double data[2] = {rl->l->fbcoord[0], rl->l->fbcoord[1]};
+ double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1};
+ double r = 1, sr = 1;
+
+ if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) {
+ return lineart_get_bounding_area(rb, data[0], data[1]);
+ }
+
+ if (lineart_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, LU, RU, &sr) && sr < r &&
+ sr > 0) {
+ r = sr;
+ }
+ if (lineart_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, LB, RB, &sr) && sr < r &&
+ sr > 0) {
+ r = sr;
+ }
+ if (lineart_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, LB, LU, &sr) && sr < r &&
+ sr > 0) {
+ r = sr;
+ }
+ if (lineart_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, RB, RU, &sr) && sr < r &&
+ sr > 0) {
+ r = sr;
+ }
+ interp_v2_v2v2_db(data, rl->l->fbcoord, rl->r->fbcoord, r);
+
+ return lineart_get_bounding_area(rb, data[0], data[1]);
+}
+
+/* This march along one render line in image space and
+ * get the next bounding area the line is crossing. */
+static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this,
+ LineartLine *rl,
+ double x,
+ double y,
+ double k,
+ int positive_x,
+ int positive_y,
+ double *next_x,
+ double *next_y)
+{
+ double rx, ry, ux, uy, lx, ly, bx, by;
+ double r1, r2;
+ LineartBoundingArea *ba;
+
+ /* If we are marching towards the right. */
+ if (positive_x > 0) {
+ rx = this->r;
+ ry = y + k * (rx - x);
+
+ /* If we are marching towards the top. */
+ if (positive_y > 0) {
+ uy = this->u;
+ ux = x + (uy - y) / k;
+ r1 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], rx);
+ r2 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], ux);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+
+ /* We reached the right side before the top side. */
+ if (r1 <= r2) {
+ LISTBASE_FOREACH (LinkData *, lip, &this->rp) {
+ ba = lip->data;
+ if (ba->u >= ry && ba->b < ry) {
+ *next_x = rx;
+ *next_y = ry;
+ return ba;
+ }
+ }
+ }
+ /* We reached the top side before the right side. */
+ else {
+ LISTBASE_FOREACH (LinkData *, lip, &this->up) {
+ ba = lip->data;
+ if (ba->r >= ux && ba->l < ux) {
+ *next_x = ux;
+ *next_y = uy;
+ return ba;
+ }
+ }
+ }
+ }
+ /* If we are marching towards the bottom. */
+ else if (positive_y < 0) {
+ by = this->b;
+ bx = x + (by - y) / k;
+ r1 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], rx);
+ r2 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], bx);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ LISTBASE_FOREACH (LinkData *, lip, &this->rp) {
+ ba = lip->data;
+ if (ba->u >= ry && ba->b < ry) {
+ *next_x = rx;
+ *next_y = ry;
+ return ba;
+ }
+ }
+ }
+ else {
+ LISTBASE_FOREACH (LinkData *, lip, &this->bp) {
+ ba = lip->data;
+ if (ba->r >= bx && ba->l < bx) {
+ *next_x = bx;
+ *next_y = by;
+ return ba;
+ }
+ }
+ }
+ }
+ /* If the line is compeletely horizontal, in which Y diffence == 0. */
+ else {
+ r1 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], this->r);
+ if (r1 > 1) {
+ return 0;
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &this->rp) {
+ ba = lip->data;
+ if (ba->u >= y && ba->b < y) {
+ *next_x = this->r;
+ *next_y = y;
+ return ba;
+ }
+ }
+ }
+ }
+
+ /* If we are marching towards the left. */
+ else if (positive_x < 0) {
+ lx = this->l;
+ ly = y + k * (lx - x);
+
+ /* If we are marching towards the top. */
+ if (positive_y > 0) {
+ uy = this->u;
+ ux = x + (uy - y) / k;
+ r1 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], lx);
+ r2 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], ux);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ LISTBASE_FOREACH (LinkData *, lip, &this->lp) {
+ ba = lip->data;
+ if (ba->u >= ly && ba->b < ly) {
+ *next_x = lx;
+ *next_y = ly;
+ return ba;
+ }
+ }
+ }
+ else {
+ LISTBASE_FOREACH (LinkData *, lip, &this->up) {
+ ba = lip->data;
+ if (ba->r >= ux && ba->l < ux) {
+ *next_x = ux;
+ *next_y = uy;
+ return ba;
+ }
+ }
+ }
+ }
+
+ /* If we are marching towards the bottom. */
+ else if (positive_y < 0) {
+ by = this->b;
+ bx = x + (by - y) / k;
+ r1 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], lx);
+ r2 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], bx);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ LISTBASE_FOREACH (LinkData *, lip, &this->lp) {
+ ba = lip->data;
+ if (ba->u >= ly && ba->b < ly) {
+ *next_x = lx;
+ *next_y = ly;
+ return ba;
+ }
+ }
+ }
+ else {
+ LISTBASE_FOREACH (LinkData *, lip, &this->bp) {
+ ba = lip->data;
+ if (ba->r >= bx && ba->l < bx) {
+ *next_x = bx;
+ *next_y = by;
+ return ba;
+ }
+ }
+ }
+ }
+ /* Again, horizontal. */
+ else {
+ r1 = ratiod(rl->l->fbcoord[0], rl->r->fbcoord[0], this->l);
+ if (r1 > 1) {
+ return 0;
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &this->lp) {
+ ba = lip->data;
+ if (ba->u >= y && ba->b < y) {
+ *next_x = this->l;
+ *next_y = y;
+ return ba;
+ }
+ }
+ }
+ }
+ /* If the line is completely vertical, hence X difference == 0. */
+ else {
+ if (positive_y > 0) {
+ r1 = ratiod(rl->l->fbcoord[1], rl->r->fbcoord[1], this->u);
+ if (r1 > 1) {
+ return 0;
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &this->up) {
+ ba = lip->data;
+ if (ba->r > x && ba->l <= x) {
+ *next_x = x;
+ *next_y = this->u;
+ return ba;
+ }
+ }
+ }
+ else if (positive_y < 0) {
+ r1 = ratiod(rl->l->fbcoord[1], rl->r->fbcoord[1], this->b);
+ if (r1 > 1) {
+ return 0;
+ }
+ LISTBASE_FOREACH (LinkData *, lip, &this->bp) {
+ ba = lip->data;
+ if (ba->r > x && ba->l <= x) {
+ *next_x = x;
+ *next_y = this->b;
+ return ba;
+ }
+ }
+ }
+ else {
+ /* egment has no length. */
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* This is the entry point of all line art calculations. */
+int MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModifierData *lmd)
+{
+ LineartRenderBuffer *rb;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ int intersections_only = 0; /* Not used right now, but preserve for future. */
+
+ if (!scene->camera) {
+ return OPERATOR_CANCELLED;
+ }
+
+ rb = lineart_create_render_buffer(scene, lmd);
+
+ /* Triangle thread testing data size varies depending on the thread count.
+ * See definition of LineartTriangleThread for details. */
+ rb->triangle_size = lineart_triangle_size_get(scene, rb);
+
+ /* This is used to limit calculation to a certain level to save time, lines who have higher
+ * occlusion levels will get ignored. */
+ rb->max_occlusion_level = MAX2(lmd->level_start, lmd->level_end);
+
+ /* Get view vector before loading geometries, because we detect feature lines there. */
+ lineart_main_get_view_vector(rb);
+ lineart_main_load_geometries(
+ depsgraph, scene, scene->camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
+
+ if (!rb->vertex_buffer_pointers.first) {
+ /* No geometry loaded, return early. */
+ return OPERATOR_FINISHED;
+ }
+
+ /* Initialize the bounding box acceleration structure, it's a lot like BVH in 3D. */
+ lineart_main_bounding_area_make_initial(rb);
+
+ /* We need to get cut into triangles that are crossing near/far plans, only this way can we get
+ * correct coordinates of those clipped lines. Done in two steps,
+ * setting clip_far==false for near plane. */
+ lineart_main_cull_triangles(rb, false);
+ /* clip_far==true for far plane. */
+ lineart_main_cull_triangles(rb, true);
+
+ /* At this point triangle adjacent info pointers is no longer needed, free them. */
+ lineart_main_free_adjacent_data(rb);
+
+ /* Do the perspective division after clipping is done. */
+ lineart_main_perspective_division(rb);
+
+ /* Triangle intersections are done here during sequential adding of them. Only after this,
+ * triangles and lines are all linked with acceleration structure, and the 2D occlusion stage can
+ * do its job. */
+ lineart_main_add_triangles(rb);
+
+ /* Link lines to acceleration structure, this can only be done after perspective division, if we
+ * do it after triangles being added, the acceleration structure has already been subdivided,
+ * this way we do less list manipulations. */
+ lineart_main_link_lines(rb);
+
+ /* "intersection_only" is preserved for being called in a standalone fashion.
+ * If so the data will already be available at the stage. Otherwise we do the occlusion and
+ * chaining etc.*/
+
+ if (!intersections_only) {
+
+ /* Occlusion is work-and-wait. This call will not return before work is completed. */
+ lineart_main_occlusion_begin(rb);
+
+ /* Chaining is all single threaded. See lineart_chain.c
+ * In this particular call, only lines that are geometrically connected (share the _exact_ same
+ * end point) will be chained together. */
+ MOD_lineart_chain_feature_lines(rb);
+
+ /* We are unable to take care of occlusion if we only connect end points, so here we do a spit,
+ * where the splitting point could be any cut in rl->segments. */
+ MOD_lineart_chain_split_for_fixed_occlusion(rb);
+
+ /* Then we connect chains based on the _proximity_ of their end points in geometry or image
+ * space, here's the place threashold value gets involved. */
+
+ /* If both chaining thresholds are zero, then we allow at least image space chaining to do a
+ * little bit of work so we don't end up in fragmented strokes. */
+ float *t_image = &lmd->chaining_image_threshold;
+ float *t_geom = &lmd->chaining_geometry_threshold;
+ if (*t_image < FLT_EPSILON && *t_geom < FLT_EPSILON) {
+ *t_geom = 0.0f;
+ *t_image = 0.001f;
+ }
+
+ /* do_geometry_space = true. */
+ MOD_lineart_chain_connect(rb, true);
+
+ /* After chaining, we need to clear flags so we can do another round in image space. */
+ MOD_lineart_chain_clear_picked_flag(rb);
+
+ /* do_geometry_space = false (it's image_space). */
+ MOD_lineart_chain_connect(rb, false);
+
+ /* Clear again so we don't confuse GPencil generation calls. */
+ MOD_lineart_chain_clear_picked_flag(rb);
+
+ /* This configuration ensures there won't be accidental lost of short unchained segments. */
+ MOD_lineart_chain_discard_short(rb, MIN3(*t_image, *t_geom, 0.001f) - FLT_EPSILON);
+
+ if (rb->angle_splitting_threshold > FLT_EPSILON) {
+ MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
+ }
+ }
+
+ if (G.debug_value == 4000) {
+ lineart_count_and_print_render_buffer_memory(rb);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int lineart_rb_line_types(LineartRenderBuffer *rb)
+{
+ int types = 0;
+ types |= rb->use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
+ types |= rb->use_crease ? LRT_EDGE_FLAG_CREASE : 0;
+ types |= rb->use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
+ types |= rb->use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
+ types |= rb->use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
+ return types;
+}
+
+static void lineart_gpencil_generate(LineartRenderBuffer *rb,
+ Depsgraph *depsgraph,
+ Object *gpencil_object,
+ float (*gp_obmat_inverse)[4],
+ bGPDlayer *UNUSED(gpl),
+ bGPDframe *gpf,
+ int level_start,
+ int level_end,
+ int material_nr,
+ Object *source_object,
+ Collection *source_collection,
+ int types,
+ unsigned char transparency_flags,
+ unsigned char transparency_mask,
+ short thickness,
+ float opacity,
+ float pre_sample_length,
+ const char *source_vgname,
+ const char *vgname,
+ int modifier_flags)
+{
+ if (rb == NULL) {
+ if (G.debug_value == 4000) {
+ printf("NULL Lineart rb!\n");
+ }
+ return;
+ }
+
+ int stroke_count = 0;
+ int color_idx = 0;
+
+ Object *orig_ob = NULL;
+ if (source_object) {
+ orig_ob = source_object->id.orig_id ? (Object *)source_object->id.orig_id : source_object;
+ }
+
+ Collection *orig_col = NULL;
+ if (source_collection) {
+ orig_col = source_collection->id.orig_id ? (Collection *)source_collection->id.orig_id :
+ source_collection;
+ }
+
+ /* (!orig_col && !orig_ob) means the whole scene is selected. */
+
+ float mat[4][4];
+ unit_m4(mat);
+
+ int enabled_types = lineart_rb_line_types(rb);
+ bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
+ bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
+ bool preserve_weight = modifier_flags & LRT_GPENCIL_SOFT_SELECTION;
+
+ LISTBASE_FOREACH (LineartLineChain *, rlc, &rb->chains) {
+
+ if (rlc->picked) {
+ continue;
+ }
+ if (!(rlc->type & (types & enabled_types))) {
+ continue;
+ }
+ if (rlc->level > level_end || rlc->level < level_start) {
+ continue;
+ }
+ if (orig_ob && orig_ob != rlc->object_ref) {
+ continue;
+ }
+ if (orig_col && rlc->object_ref) {
+ if (!BKE_collection_has_object_recursive_instanced(orig_col, (Object *)rlc->object_ref)) {
+ continue;
+ }
+ }
+ if (transparency_flags & LRT_GPENCIL_TRANSPARENCY_ENABLE) {
+ if (transparency_flags & LRT_GPENCIL_TRANSPARENCY_MATCH) {
+ if (rlc->transparency_mask != transparency_mask) {
+ continue;
+ }
+ }
+ else {
+ if (!(rlc->transparency_mask & transparency_mask)) {
+ continue;
+ }
+ }
+ }
+
+ /* Preserved: If we ever do async generation, this picked flag should be set here. */
+ /* rlc->picked = 1;. */
+
+ int array_idx = 0;
+ int count = MOD_lineart_chain_count(rlc);
+ bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, color_idx, count, thickness, false);
+
+ float *stroke_data = MEM_callocN(sizeof(float) * count * GP_PRIM_DATABUF_SIZE,
+ "line art add stroke");
+
+ LISTBASE_FOREACH (LineartLineChainItem *, rlci, &rlc->chain) {
+ stroke_data[array_idx] = rlci->gpos[0];
+ stroke_data[array_idx + 1] = rlci->gpos[1];
+ stroke_data[array_idx + 2] = rlci->gpos[2];
+ mul_m4_v3(gp_obmat_inverse, &stroke_data[array_idx]);
+ stroke_data[array_idx + 3] = 1; /* thickness. */
+ stroke_data[array_idx + 4] = opacity; /* hardness?. */
+ array_idx += 5;
+ }
+
+ BKE_gpencil_stroke_add_points(gps, stroke_data, count, mat);
+ BKE_gpencil_dvert_ensure(gps);
+ gps->mat_nr = material_nr;
+
+ MEM_freeN(stroke_data);
+
+ if (source_vgname && vgname) {
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, rlc->object_ref);
+ int gpdg = -1;
+ if ((match_output || (gpdg = BKE_object_defgroup_name_index(gpencil_object, vgname)) >= 0)) {
+ if (eval_ob && eval_ob->type == OB_MESH) {
+ int dindex = 0;
+ Mesh *me = (Mesh *)eval_ob->data;
+ if (me->dvert) {
+ LISTBASE_FOREACH (bDeformGroup *, db, &eval_ob->defbase) {
+ if ((!source_vgname) || strstr(db->name, source_vgname) == db->name) {
+ if (match_output) {
+ gpdg = BKE_object_defgroup_name_index(gpencil_object, db->name);
+ if (gpdg < 0) {
+ continue;
+ }
+ }
+ int sindex = 0, vindex;
+ LISTBASE_FOREACH (LineartLineChainItem *, rlci, &rlc->chain) {
+ vindex = rlci->index;
+ if (vindex >= me->totvert) {
+ break;
+ }
+ MDeformWeight *mdw = BKE_defvert_ensure_index(&me->dvert[vindex], dindex);
+ MDeformWeight *gdw = BKE_defvert_ensure_index(&gps->dvert[sindex], gpdg);
+ if (preserve_weight) {
+ float use_weight = mdw->weight;
+ if (invert_input) {
+ use_weight = 1 - use_weight;
+ }
+ gdw->weight = MAX2(use_weight, gdw->weight);
+ }
+ else {
+ if (mdw->weight > 0.999f) {
+ gdw->weight = 1.0f;
+ }
+ }
+ sindex++;
+ }
+ }
+ dindex++;
+ }
+ }
+ }
+ }
+ }
+
+ if (pre_sample_length > 0.0001) {
+ BKE_gpencil_stroke_sample(gpencil_object->data, gps, pre_sample_length, false);
+ }
+ if (G.debug_value == 4000) {
+ BKE_gpencil_stroke_set_random_color(gps);
+ }
+ BKE_gpencil_stroke_geometry_update(gpencil_object->data, gps);
+ stroke_count++;
+ }
+
+ if (G.debug_value == 4000) {
+ printf("LRT: Generated %d strokes.\n", stroke_count);
+ }
+}
+
+/* Wrapper for external calls. */
+void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
+ Depsgraph *depsgraph,
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ char source_type,
+ void *source_reference,
+ int level_start,
+ int level_end,
+ int mat_nr,
+ short line_types,
+ unsigned char transparency_flags,
+ unsigned char transparency_mask,
+ short thickness,
+ float opacity,
+ float pre_sample_length,
+ const char *source_vgname,
+ const char *vgname,
+ int modifier_flags)
+{
+
+ if (!gpl || !gpf || !ob) {
+ return;
+ }
+
+ Object *source_object = NULL;
+ Collection *source_collection = NULL;
+ short use_types = 0;
+ if (source_type == LRT_SOURCE_OBJECT) {
+ if (!source_reference) {
+ return;
+ }
+ source_object = (Object *)source_reference;
+ /* Note that intersection lines will only be in collection. */
+ use_types = line_types & (~LRT_EDGE_FLAG_INTERSECTION);
+ }
+ else if (source_type == LRT_SOURCE_COLLECTION) {
+ if (!source_reference) {
+ return;
+ }
+ source_collection = (Collection *)source_reference;
+ use_types = line_types;
+ }
+ else {
+ /* Whole scene. */
+ use_types = line_types;
+ }
+ float gp_obmat_inverse[4][4];
+ invert_m4_m4(gp_obmat_inverse, ob->obmat);
+ lineart_gpencil_generate(rb,
+ depsgraph,
+ ob,
+ gp_obmat_inverse,
+ gpl,
+ gpf,
+ level_start,
+ level_end,
+ mat_nr,
+ source_object,
+ source_collection,
+ use_types,
+ transparency_flags,
+ transparency_mask,
+ thickness,
+ opacity,
+ pre_sample_length,
+ source_vgname,
+ vgname,
+ modifier_flags);
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
new file mode 100644
index 00000000000..34f6e62546d
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
@@ -0,0 +1,113 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#pragma once
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "DNA_lineart_types.h"
+
+#include <math.h>
+#include <string.h>
+
+struct LineartStaticMemPool;
+struct LineartStaticMemPoolNode;
+struct LineartLine;
+struct LineartRenderBuffer;
+
+void *lineart_list_append_pointer_pool(ListBase *h, struct LineartStaticMemPool *smp, void *data);
+void *lineart_list_append_pointer_pool_sized(ListBase *h,
+ struct LineartStaticMemPool *smp,
+ void *data,
+ int size);
+void *list_push_pointer_static(ListBase *h, struct LineartStaticMemPool *smp, void *p);
+void *list_push_pointer_static_sized(ListBase *h,
+ struct LineartStaticMemPool *smp,
+ void *p,
+ int size);
+
+void *lineart_list_pop_pointer_no_free(ListBase *h);
+void lineart_list_remove_pointer_item_no_free(ListBase *h, LinkData *lip);
+
+struct LineartStaticMemPoolNode *lineart_mem_new_static_pool(struct LineartStaticMemPool *smp,
+ size_t size);
+void *lineart_mem_aquire(struct LineartStaticMemPool *smp, size_t size);
+void *lineart_mem_aquire_thread(struct LineartStaticMemPool *smp, size_t size);
+void lineart_mem_destroy(struct LineartStaticMemPool *smp);
+
+void lineart_prepend_line_direct(struct LineartLine **first, void *node);
+void lineart_prepend_pool(LinkNode **first, struct LineartStaticMemPool *smp, void *link);
+
+void lineart_matrix_ortho_44d(double (*mProjection)[4],
+ double xMin,
+ double xMax,
+ double yMin,
+ double yMax,
+ double zMin,
+ double zMax);
+void lineart_matrix_perspective_44d(
+ double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax);
+
+int lineart_count_intersection_segment_count(struct LineartRenderBuffer *rb);
+
+void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb);
+
+#define LRT_ITER_ALL_LINES_BEGIN \
+ LineartLine *rl, *next_rl, **current_list; \
+ rl = rb->contours; \
+ for (current_list = &rb->contours; rl; rl = next_rl) { \
+ next_rl = rl->next;
+
+#define LRT_ITER_ALL_LINES_NEXT \
+ while (!next_rl) { \
+ if (current_list == &rb->contours) { \
+ current_list = &rb->crease_lines; \
+ } \
+ else if (current_list == &rb->crease_lines) { \
+ current_list = &rb->material_lines; \
+ } \
+ else if (current_list == &rb->material_lines) { \
+ current_list = &rb->edge_marks; \
+ } \
+ else if (current_list == &rb->edge_marks) { \
+ current_list = &rb->intersection_lines; \
+ } \
+ else { \
+ break; \
+ } \
+ next_rl = *current_list; \
+ }
+
+#define LRT_ITER_ALL_LINES_END \
+ LRT_ITER_ALL_LINES_NEXT \
+ }
+
+#define LRT_BOUND_AREA_CROSSES(b1, b2) \
+ ((b1)[0] < (b2)[1] && (b1)[1] > (b2)[0] && (b1)[3] < (b2)[2] && (b1)[2] > (b2)[3])
+
+/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function
+ * efficiently. */
+#define LRT_BA_ROWS 4
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
new file mode 100644
index 00000000000..56490a84279
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -0,0 +1,439 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_collection.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+
+#include "UI_resources.h"
+
+#include "MOD_gpencil_lineart.h"
+#include "MOD_lineart.h"
+
+#include "lineart_intern.h"
+
+static void clear_strokes(Object *ob, GpencilModifierData *md, int frame)
+{
+ if (md->type != eGpencilModifierType_Lineart) {
+ return;
+ }
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
+ if (!gpl) {
+ return;
+ }
+ bGPDframe *gpf = BKE_gpencil_layer_frame_find(gpl, frame);
+
+ if (!gpf) {
+ /* No greasepencil frame found. */
+ return;
+ }
+
+ BKE_gpencil_layer_frame_delete(gpl, gpf);
+}
+
+static bool bake_strokes(Object *ob, Depsgraph *dg, GpencilModifierData *md, int frame)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
+ if (!gpl) {
+ return false;
+ }
+ bool only_use_existing_gp_frames = false;
+ bGPDframe *gpf = (only_use_existing_gp_frames ?
+ BKE_gpencil_layer_frame_find(gpl, frame) :
+ BKE_gpencil_layer_frame_get(gpl, frame, GP_GETFRAME_ADD_NEW));
+
+ if (!gpf) {
+ /* No greasepencil frame created or found. */
+ return false;
+ }
+
+ MOD_lineart_compute_feature_lines(dg, lmd);
+
+ MOD_lineart_gpencil_generate(
+ lmd->render_buffer,
+ dg,
+ ob,
+ gpl,
+ gpf,
+ lmd->source_type,
+ lmd->source_type == LRT_SOURCE_OBJECT ? (void *)lmd->source_object :
+ (void *)lmd->source_collection,
+ lmd->level_start,
+ lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
+ lmd->target_material ? BKE_gpencil_object_material_index_get(ob, lmd->target_material) : 0,
+ lmd->line_types,
+ lmd->transparency_flags,
+ lmd->transparency_mask,
+ lmd->thickness,
+ lmd->opacity,
+ lmd->pre_sample_length,
+ lmd->source_vertex_group,
+ lmd->vgname,
+ lmd->flags);
+
+ MOD_lineart_destroy_render_data(lmd);
+
+ return true;
+}
+
+typedef struct LineartBakeJob {
+ wmWindowManager *wm;
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+
+ /* C or ob must have one != NULL. */
+ bContext *C;
+ LinkNode *objects;
+ Scene *scene;
+ Depsgraph *dg;
+ int frame;
+ int frame_begin;
+ int frame_end;
+ int frame_orig;
+ int frame_increment;
+ bool overwrite_frames;
+} LineartBakeJob;
+
+static bool lineart_gpencil_bake_single_target(LineartBakeJob *bj, Object *ob, int frame)
+{
+ bool touched = false;
+ if (ob->type != OB_GPENCIL || G.is_break) {
+ return false;
+ }
+
+ if (bj->overwrite_frames) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ clear_strokes(ob, md, frame);
+ }
+ }
+
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (bake_strokes(ob, bj->dg, md, frame)) {
+ touched = true;
+ }
+ }
+
+ return touched;
+}
+
+static void lineart_gpencil_guard_modifiers(LineartBakeJob *bj)
+{
+ for (LinkNode *l = bj->objects; l; l = l->next) {
+ Object *ob = l->link;
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Lineart) {
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ lmd->flags |= LRT_GPENCIL_IS_BAKED;
+ }
+ }
+ }
+}
+
+static void lineart_gpencil_bake_startjob(void *customdata,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ LineartBakeJob *bj = (LineartBakeJob *)customdata;
+ bj->stop = stop;
+ bj->do_update = do_update;
+ bj->progress = progress;
+
+ lineart_gpencil_guard_modifiers(bj);
+
+ for (int frame = bj->frame_begin; frame <= bj->frame_end; frame += bj->frame_increment) {
+
+ if (G.is_break) {
+ G.is_break = false;
+ break;
+ }
+
+ BKE_scene_frame_set(bj->scene, frame);
+ BKE_scene_graph_update_for_newframe(bj->dg);
+
+ for (LinkNode *l = bj->objects; l; l = l->next) {
+ Object *ob = l->link;
+ if (lineart_gpencil_bake_single_target(bj, ob, frame)) {
+ DEG_id_tag_update((struct ID *)ob->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(bj->C, NC_GPENCIL | ND_DATA | NA_EDITED, ob);
+ }
+ }
+
+ /* Update and refresh the progress bar. */
+ *bj->progress = (float)(frame - bj->frame_begin) / (bj->frame_end - bj->frame_begin);
+ *bj->do_update = true;
+ }
+
+ /* This need to be reset manually. */
+ G.is_break = false;
+
+ /* Restore original frame. */
+ BKE_scene_frame_set(bj->scene, bj->frame_orig);
+ BKE_scene_graph_update_for_newframe(bj->dg);
+}
+
+static void lineart_gpencil_bake_endjob(void *customdata)
+{
+ LineartBakeJob *bj = customdata;
+
+ WM_set_locked_interface(CTX_wm_manager(bj->C), false);
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, bj->scene);
+
+ for (LinkNode *l = bj->objects; l; l = l->next) {
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, (Object *)l->link);
+ }
+
+ BLI_linklist_free(bj->objects, NULL);
+}
+
+static int lineart_gpencil_bake_common(bContext *C,
+ wmOperator *op,
+ bool bake_all_targets,
+ bool do_background)
+{
+ LineartBakeJob *bj = MEM_callocN(sizeof(LineartBakeJob), "LineartBakeJob");
+
+ if (!bake_all_targets) {
+ Object *ob = CTX_data_active_object(C);
+ if (!ob || ob->type != OB_GPENCIL) {
+ WM_report(RPT_ERROR, "No active object or active object isn't a GPencil object.");
+ return OPERATOR_FINISHED;
+ }
+ BLI_linklist_prepend(&bj->objects, ob);
+ }
+ else {
+ /* CTX_DATA_BEGIN is not available for interating in objects while using the Job system. */
+ CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
+ if (ob->type == OB_GPENCIL) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Lineart) {
+ BLI_linklist_prepend(&bj->objects, ob);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ bj->C = C;
+ Scene *scene = CTX_data_scene(C);
+ bj->scene = scene;
+ bj->dg = CTX_data_depsgraph_pointer(C);
+ bj->frame_begin = scene->r.sfra;
+ bj->frame_end = scene->r.efra;
+ bj->frame_orig = scene->r.cfra;
+ bj->frame_increment = scene->r.frame_step;
+ bj->overwrite_frames = true;
+
+ if (do_background) {
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Line Art",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_LINEART);
+
+ WM_jobs_customdata_set(wm_job, bj, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.1, NC_GPENCIL | ND_DATA | NA_EDITED, NC_GPENCIL | ND_DATA | NA_EDITED);
+ WM_jobs_callbacks(
+ wm_job, lineart_gpencil_bake_startjob, NULL, NULL, lineart_gpencil_bake_endjob);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float pseduo_progress;
+ short pseduo_do_update;
+ lineart_gpencil_bake_startjob(bj, NULL, &pseduo_do_update, &pseduo_progress);
+
+ BLI_linklist_free(bj->objects, NULL);
+ MEM_freeN(bj);
+
+ return OPERATOR_FINISHED;
+}
+
+static int lineart_gpencil_bake_strokes_all_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return lineart_gpencil_bake_common(C, op, true, true);
+}
+static int lineart_gpencil_bake_strokes_all_exec(bContext *C, wmOperator *op)
+{
+ return lineart_gpencil_bake_common(C, op, true, false);
+}
+static int lineart_gpencil_bake_strokes_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return lineart_gpencil_bake_common(C, op, false, true);
+}
+static int lineart_gpencil_bake_strokes_exec(bContext *C, wmOperator *op)
+{
+ return lineart_gpencil_bake_common(C, op, false, false);
+
+ return OPERATOR_FINISHED;
+}
+static int lineart_gpencil_bake_strokes_commom_modal(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ Scene *scene = (Scene *)op->customdata;
+
+ /* no running blender, remove handler and pass through. */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_LINEART)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void lineart_gpencil_clear_strokes_exec_common(Object *ob)
+{
+ if (ob->type != OB_GPENCIL) {
+ return;
+ }
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type != eGpencilModifierType_Lineart) {
+ continue;
+ }
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
+ if (!gpl) {
+ continue;
+ }
+ BKE_gpencil_free_frames(gpl);
+
+ md->mode |= eGpencilModifierMode_Realtime | eGpencilModifierMode_Render;
+
+ lmd->flags &= (~LRT_GPENCIL_IS_BAKED);
+ }
+ DEG_id_tag_update((struct ID *)ob->data, ID_RECALC_GEOMETRY);
+}
+
+static int lineart_gpencil_clear_strokes_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ lineart_gpencil_clear_strokes_exec_common(ob);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, ob);
+
+ return OPERATOR_FINISHED;
+}
+static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op)
+{
+ CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
+ lineart_gpencil_clear_strokes_exec_common(ob);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, ob);
+ }
+ CTX_DATA_END;
+
+ BKE_report(op->reports, RPT_INFO, "All line art objects are now cleared.");
+
+ return OPERATOR_FINISHED;
+}
+
+/* Bake all line art modifiers on the current object. */
+void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
+{
+ ot->name = "Bake Line Art";
+ ot->description = "Bake Line Art for current GPencil object";
+ ot->idname = "OBJECT_OT_lineart_bake_strokes";
+
+ ot->invoke = lineart_gpencil_bake_strokes_invoke;
+ ot->exec = lineart_gpencil_bake_strokes_exec;
+ ot->modal = lineart_gpencil_bake_strokes_commom_modal;
+}
+
+/* Bake all lineart objects in the scene. */
+void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
+{
+ ot->name = "Bake Line Art (All)";
+ ot->description = "Bake all Grease Pencil objects that have a line art modifier";
+ ot->idname = "OBJECT_OT_lineart_bake_strokes_all";
+
+ ot->invoke = lineart_gpencil_bake_strokes_all_invoke;
+ ot->exec = lineart_gpencil_bake_strokes_all_exec;
+ ot->modal = lineart_gpencil_bake_strokes_commom_modal;
+}
+
+/* clear all line art modifiers on the current object. */
+void OBJECT_OT_lineart_clear(wmOperatorType *ot)
+{
+ ot->name = "Clear Baked Line Art";
+ ot->description = "Clear all strokes in current GPencil obejct";
+ ot->idname = "OBJECT_OT_lineart_clear";
+
+ ot->exec = lineart_gpencil_clear_strokes_exec;
+}
+
+/* clear all lineart objects in the scene. */
+void OBJECT_OT_lineart_clear_all(wmOperatorType *ot)
+{
+ ot->name = "Clear Baked Line Art (All)";
+ ot->description = "Clear all strokes in all Grease Pencil objects that have a line art modifier";
+ ot->idname = "OBJECT_OT_lineart_clear_all";
+
+ ot->exec = lineart_gpencil_clear_strokes_all_exec;
+}
+
+void WM_operatortypes_lineart(void)
+{
+ WM_operatortype_append(OBJECT_OT_lineart_bake_strokes);
+ WM_operatortype_append(OBJECT_OT_lineart_bake_strokes_all);
+ WM_operatortype_append(OBJECT_OT_lineart_clear);
+ WM_operatortype_append(OBJECT_OT_lineart_clear_all);
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
new file mode 100644
index 00000000000..8e8c39391c3
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
@@ -0,0 +1,233 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+/* #include <time.h> */
+#include "MEM_guardedalloc.h"
+#include "MOD_lineart.h"
+#include <math.h>
+
+#include "lineart_intern.h"
+
+/* Line art memory and list helper */
+
+void *lineart_list_append_pointer_pool(ListBase *h, LineartStaticMemPool *smp, void *data)
+{
+ LinkData *lip;
+ if (h == NULL) {
+ return 0;
+ }
+ lip = lineart_mem_aquire(smp, sizeof(LinkData));
+ lip->data = data;
+ BLI_addtail(h, lip);
+ return lip;
+}
+void *lineart_list_append_pointer_pool_sized(ListBase *h,
+ LineartStaticMemPool *smp,
+ void *data,
+ int size)
+{
+ LinkData *lip;
+ if (h == NULL) {
+ return 0;
+ }
+ lip = lineart_mem_aquire(smp, size);
+ lip->data = data;
+ BLI_addtail(h, lip);
+ return lip;
+}
+
+void *lineart_list_pop_pointer_no_free(ListBase *h)
+{
+ LinkData *lip;
+ void *rev = 0;
+ if (h == NULL) {
+ return 0;
+ }
+ lip = BLI_pophead(h);
+ rev = lip ? lip->data : 0;
+ return rev;
+}
+void lineart_list_remove_pointer_item_no_free(ListBase *h, LinkData *lip)
+{
+ BLI_remlink(h, (void *)lip);
+}
+
+LineartStaticMemPoolNode *lineart_mem_new_static_pool(LineartStaticMemPool *smp, size_t size)
+{
+ size_t set_size = size;
+ if (set_size < LRT_MEMORY_POOL_64MB) {
+ set_size = LRT_MEMORY_POOL_64MB; /* Prevent too many small allocations. */
+ }
+ size_t total_size = size + sizeof(LineartStaticMemPoolNode);
+ LineartStaticMemPoolNode *smpn = MEM_callocN(total_size, "mempool");
+ smpn->size = total_size;
+ smpn->used_byte = sizeof(LineartStaticMemPoolNode);
+ BLI_addhead(&smp->pools, smpn);
+ return smpn;
+}
+void *lineart_mem_aquire(LineartStaticMemPool *smp, size_t size)
+{
+ LineartStaticMemPoolNode *smpn = smp->pools.first;
+ void *ret;
+
+ if (!smpn || (smpn->used_byte + size) > smpn->size) {
+ smpn = lineart_mem_new_static_pool(smp, size);
+ }
+
+ ret = ((unsigned char *)smpn) + smpn->used_byte;
+
+ smpn->used_byte += size;
+
+ return ret;
+}
+void *lineart_mem_aquire_thread(LineartStaticMemPool *smp, size_t size)
+{
+ void *ret;
+
+ BLI_spin_lock(&smp->lock_mem);
+
+ LineartStaticMemPoolNode *smpn = smp->pools.first;
+
+ if (!smpn || (smpn->used_byte + size) > smpn->size) {
+ smpn = lineart_mem_new_static_pool(smp, size);
+ }
+
+ ret = ((unsigned char *)smpn) + smpn->used_byte;
+
+ smpn->used_byte += size;
+
+ BLI_spin_unlock(&smp->lock_mem);
+
+ return ret;
+}
+void lineart_mem_destroy(LineartStaticMemPool *smp)
+{
+ LineartStaticMemPoolNode *smpn;
+ while ((smpn = BLI_pophead(&smp->pools)) != NULL) {
+ MEM_freeN(smpn);
+ }
+}
+
+void lineart_prepend_line_direct(LineartLine **first, void *node)
+{
+ LineartLine *ln = (LineartLine *)node;
+ ln->next = (*first);
+ (*first) = ln;
+}
+
+void lineart_prepend_pool(LinkNode **first, LineartStaticMemPool *smp, void *link)
+{
+ LinkNode *ln = lineart_mem_aquire_thread(smp, sizeof(LinkNode));
+ ln->next = (*first);
+ ln->link = link;
+ (*first) = ln;
+}
+
+/* =======================================================================[str] */
+
+void lineart_matrix_perspective_44d(
+ double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax)
+{
+ double yMax;
+ double yMin;
+ double xMin;
+ double xMax;
+
+ if (fAspect < 1) {
+ yMax = zMin * tan(fFov_rad * 0.5f);
+ yMin = -yMax;
+ xMin = yMin * fAspect;
+ xMax = -xMin;
+ }
+ else {
+ xMax = zMin * tan(fFov_rad * 0.5f);
+ xMin = -xMax;
+ yMin = xMin / fAspect;
+ yMax = -yMin;
+ }
+
+ unit_m4_db(mProjection);
+
+ mProjection[0][0] = (2.0f * zMin) / (xMax - xMin);
+ mProjection[1][1] = (2.0f * zMin) / (yMax - yMin);
+ mProjection[2][0] = (xMax + xMin) / (xMax - xMin);
+ mProjection[2][1] = (yMax + yMin) / (yMax - yMin);
+ mProjection[2][2] = -((zMax + zMin) / (zMax - zMin));
+ mProjection[2][3] = -1.0f;
+ mProjection[3][2] = -((2.0f * (zMax * zMin)) / (zMax - zMin));
+ mProjection[3][3] = 0.0f;
+}
+void lineart_matrix_ortho_44d(double (*mProjection)[4],
+ double xMin,
+ double xMax,
+ double yMin,
+ double yMax,
+ double zMin,
+ double zMax)
+{
+ unit_m4_db(mProjection);
+
+ mProjection[0][0] = 2.0f / (xMax - xMin);
+ mProjection[1][1] = 2.0f / (yMax - yMin);
+ mProjection[2][2] = -2.0f / (zMax - zMin);
+ mProjection[3][0] = -((xMax + xMin) / (xMax - xMin));
+ mProjection[3][1] = -((yMax + yMin) / (yMax - yMin));
+ mProjection[3][2] = -((zMax + zMin) / (zMax - zMin));
+ mProjection[3][3] = 1.0f;
+}
+
+void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
+{
+ size_t total = 0;
+ size_t sum_this = 0;
+ size_t count_this = 0;
+
+ LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) {
+ count_this++;
+ sum_this += LRT_MEMORY_POOL_64MB;
+ }
+ printf("LANPR Memory allocated %lu Standalone nodes, total %lu Bytes.\n", count_this, sum_this);
+ total += sum_this;
+ sum_this = 0;
+ count_this = 0;
+
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->line_buffer_pointers) {
+ count_this++;
+ sum_this += reln->element_count * sizeof(LineartLine);
+ }
+ printf(" allocated %lu edge blocks, total %lu Bytes.\n", count_this, sum_this);
+ total += sum_this;
+ sum_this = 0;
+ count_this = 0;
+
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ count_this++;
+ sum_this += reln->element_count * rb->triangle_size;
+ }
+ printf(" allocated %lu triangle blocks, total %lu Bytes.\n", count_this, sum_this);
+ total += sum_this;
+ sum_this = 0;
+ count_this = 0;
+}
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index e56dcd16528..062741a6270 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -606,7 +606,7 @@ void immUniform4fv(const char *name, const float data[4])
/* Note array index is not supported for name (i.e: "array[0]"). */
void immUniformArray4fv(const char *name, const float *data, int count)
{
- GPU_shader_uniform_4fv_array(imm->shader, name, count, (float(*)[4])data);
+ GPU_shader_uniform_4fv_array(imm->shader, name, count, (const float(*)[4])data);
}
void immUniformMatrix4fv(const char *name, const float data[4][4])
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index 24cdea74347..2ae50d913da 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -736,7 +736,7 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di
int depthbits = 24;
depth_fac = 1.0f / (float)((1 << depthbits) - 1);
}
- offs = (-1.0 / winmat[2][2]) * dist * depth_fac;
+ ofs = (-1.0 / winmat[2][2]) * dist * depth_fac;
UNUSED_VARS(viewdist);
#endif
@@ -765,10 +765,10 @@ void GPU_polygon_offset(float viewdist, float dist)
/* dist is from camera to center point */
- float offs = GPU_polygon_offset_calc(winmat, viewdist, dist);
+ float ofs = GPU_polygon_offset_calc(winmat, viewdist, dist);
- winmat[3][2] -= offs;
- offset += offs;
+ winmat[3][2] -= ofs;
+ offset += ofs;
}
else {
winmat[3][2] += offset;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
index 4567429f645..9ce2a1be015 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
@@ -2,7 +2,7 @@
* 2D Quadratic Bezier thick line drawing
*/
-#define MID_VERTEX 57
+#define MID_VERTEX 65
/* u is position along the curve, defining the tangent space.
* v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */
@@ -17,6 +17,7 @@ in vec2 P1;
in vec2 P2;
in vec2 P3;
in ivec4 colid_doarrow;
+in ivec2 domuted;
uniform vec4 colors[6];
@@ -24,6 +25,7 @@ uniform vec4 colors[6];
# define colEnd colors[colid_doarrow[1]]
# define colShadow colors[colid_doarrow[2]]
# define doArrow (colid_doarrow[3] != 0)
+# define doMuted (domuted[0] != 0)
#else
/* Single curve drawcall, use uniform. */
@@ -36,6 +38,7 @@ uniform vec2 bezierPts[4];
uniform vec4 colors[3];
uniform bool doArrow;
+uniform bool doMuted;
# define colShadow colors[0]
# define colStart colors[1]
@@ -90,13 +93,18 @@ void main(void)
/* Second pass */
finalColor = mix(colStart, colEnd, uv.x);
expand_dist *= 0.5;
+ if (doMuted) {
+ finalColor[3] = 0.65;
+ }
}
/* Expand into a line */
gl_Position.xy += exp_axis * expandSize * expand_dist;
- /* if arrow */
- if (expand.y != 1.0 && !doArrow) {
+ /* If the link is not muted or is not a reroute arrow the points are squashed to the center of
+ * the line. Magic numbers are defined in drawnode.c */
+ if ((expand.x == 1.0 && !doMuted) ||
+ (expand.y != 1.0 && (pos.x < 0.70 || pos.x > 0.71) && !doArrow)) {
gl_Position.xy *= 0.0;
}
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
index 0231aeca04b..12921a31b23 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -3,19 +3,21 @@ void node_ambient_occlusion(vec4 color,
float dist,
vec3 normal,
const float inverted,
+ const float sample_count,
out vec4 result_color,
out float result_ao)
{
vec3 bent_normal;
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, 8.0);
+ OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count);
vec3 V = cameraVec(worldPosition);
vec3 N = normalize(normal);
vec3 Ng = safe_normalize(cross(dFdx(worldPosition), dFdy(worldPosition)));
+ float unused_error;
vec3 unused;
- occlusion_eval(data, V, N, Ng, inverted, result_ao, unused);
+ occlusion_eval(data, V, N, Ng, inverted, result_ao, unused_error, unused);
result_color = result_ao * color;
}
#else
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index 49c8973a8ce..2e0515e324e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -193,7 +193,7 @@ void node_bsdf_principled(vec4 base_color,
result.radiance *= alpha;
result.ssr_data.rgb *= alpha;
# ifdef USE_SSS
- result.sss_irradiance *= alpha;
+ result.sss_albedo *= alpha;
# endif
}
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index 31dca888732..89e648a7d6a 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -32,7 +32,6 @@ extern "C" {
struct ImBuf;
struct OCIO_ConstCPUProcessorRcPtr;
-struct OCIO_ConstProcessorRcPtr;
extern float imbuf_luma_coefficients[3];
extern float imbuf_xyz_to_rgb[3][3];
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index c9581c108c0..edaa1b973d0 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -27,6 +27,7 @@
#include "BLI_endian_switch.h"
#include "BLI_fileops.h"
#include "BLI_ghash.h"
+#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_threads.h"
@@ -477,7 +478,6 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
struct proxy_output_ctx *rv = MEM_callocN(sizeof(struct proxy_output_ctx), "alloc_proxy_output");
char fname[FILE_MAX];
- int ffmpeg_quality;
rv->proxy_size = proxy_size;
rv->anim = anim;
@@ -496,12 +496,15 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
rv->st->id = 0;
rv->c = rv->st->codec;
- rv->c->thread_count = BLI_system_thread_count();
- rv->c->thread_type = FF_THREAD_SLICE;
rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
- rv->c->codec_id = AV_CODEC_ID_MJPEG;
+ rv->c->codec_id = AV_CODEC_ID_H264;
rv->c->width = width;
rv->c->height = height;
+ rv->c->gop_size = 2;
+ rv->c->max_b_frames = 0;
+ /* Correct wrong default ffmpeg param which crash x264. */
+ rv->c->qmin = 10;
+ rv->c->qmax = 51;
rv->of->oformat->video_codec = rv->c->codec_id;
rv->codec = avcodec_find_encoder(rv->c->codec_id);
@@ -527,11 +530,19 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
rv->c->time_base.num = 1;
rv->st->time_base = rv->c->time_base;
- /* there's no way to set JPEG quality in the same way as in AVI JPEG and image sequence,
- * but this seems to be giving expected quality result */
- ffmpeg_quality = (int)(1.0f + 30.0f * (1.0f - (float)quality / 100.0f) + 0.5f);
- av_opt_set_int(rv->c, "qmin", ffmpeg_quality, 0);
- av_opt_set_int(rv->c, "qmax", ffmpeg_quality, 0);
+ /* This range matches eFFMpegCrf. Crf_range_min corresponds to lowest quality, crf_range_max to
+ * highest quality. */
+ const int crf_range_min = 32;
+ const int crf_range_max = 17;
+ int crf = round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min);
+
+ AVDictionary *codec_opts = NULL;
+ /* High quality preset value. */
+ av_dict_set_int(&codec_opts, "crf", crf, 0);
+ /* Prefer smaller filesize. */
+ av_dict_set(&codec_opts, "preset", "slow", 0);
+ /* Thread count. */
+ av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0);
if (rv->of->flags & AVFMT_GLOBALHEADER) {
rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
@@ -545,7 +556,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
return 0;
}
- avcodec_open2(rv->c, rv->codec, NULL);
+ avcodec_open2(rv->c, rv->codec, &codec_opts);
rv->orig_height = av_get_cropped_height_from_codec(st->codec);
@@ -783,7 +794,11 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
context->iCodecCtx->workaround_bugs = 1;
- if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) {
+ AVDictionary *codec_opts = NULL;
+ /* Thread count. */
+ av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0);
+
+ if (avcodec_open2(context->iCodecCtx, context->iCodec, &codec_opts) < 0) {
avformat_close_input(&context->iFormatCtx);
MEM_freeN(context);
return NULL;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 67e33366199..077f9bf8bdc 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -566,6 +566,16 @@ enum {
/* RESET_AFTER_USE Used by undo system to tag unchanged IDs re-used from old Main (instead of
* read from memfile). */
LIB_TAG_UNDO_OLD_ID_REUSED = 1 << 19,
+
+ /* This ID is part of a temporary #Main which is expected to be freed in a short time-frame.
+ * Don't allow assigning this to non-temporary members (since it's likely to cause errors).
+ * When set #ID.session_uuid isn't initialized, since the data isn't part of the session. */
+ LIB_TAG_TEMP_MAIN = 1 << 20,
+
+ /**
+ * The data-block is a library override that needs re-sync to its linked reference.
+ */
+ LIB_TAG_LIB_OVERRIDE_NEED_RESYNC = 1 << 21,
};
/* Tag given ID for an update in all the dependency graphs. */
@@ -722,8 +732,36 @@ typedef enum IDRecalcFlag {
FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \
FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM)
-/* IMPORTANT: this enum matches the order currently use in set_listbasepointers,
- * keep them in sync! */
+/**
+ * This enum defines the index assigned to each type of IDs in the array returned by
+ * #set_listbasepointers, and by extension, controls the default order in which each ID type is
+ * processed during standard 'foreach' looping over all IDs of a #Main data-base.
+ *
+ * About Order:
+ * ------------
+ *
+ * This is (loosely) defined with a relationship order in mind, from lowest level (ID types using,
+ * referencing almost no other ID types) to highest level (ID types potentially using many other ID
+ * types).
+ *
+ * So e.g. it ensures that this dependency chain is respected:
+ * #Material <- #Mesh <- #Object <- #Collection <- #Scene
+ *
+ * Default order of processing of IDs in 'foreach' macros (#FOREACH_MAIN_ID_BEGIN and the like),
+ * built on top of #set_listbasepointers, is actually reversed compared to the order defined here,
+ * since processing usually needs to happen on users before it happens on used IDs (when freeing
+ * e.g.).
+ *
+ * DO NOT rely on this order as being full-proofed dependency order, there are many cases were it
+ * can be violated (most obvious cases being custom properties and drivers, which can reference any
+ * other ID types).
+ *
+ * However, this order can be considered as an optimization heuristic, especially when processing
+ * relationships in a non-recursive pattern: in typical cases, a vast majority of those
+ * relationships can be processed fine in the first pass, and only few additional passes are
+ * required to address all remaining relationship cases.
+ * See e.g. how #BKE_library_unused_linked_data_set_tag is doing this.
+ */
enum {
INDEX_ID_LI = 0,
INDEX_ID_IP,
@@ -763,6 +801,8 @@ enum {
INDEX_ID_SCE,
INDEX_ID_WS,
INDEX_ID_WM,
+ /* TODO: This should probably be tweaked, #Mask and #Simulation are rather low-level types that
+ * should most likely be defined //before// #Object and geometry type indices? */
INDEX_ID_MSK,
INDEX_ID_SIM,
INDEX_ID_NULL,
diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h
index 0a80e00d456..f5fcb0b190e 100644
--- a/source/blender/makesdna/DNA_collection_types.h
+++ b/source/blender/makesdna/DNA_collection_types.h
@@ -46,6 +46,14 @@ typedef struct CollectionChild {
struct Collection *collection;
} CollectionChild;
+enum CollectionFeatureLine_Usage {
+ COLLECTION_LRT_INCLUDE = 0,
+ COLLECTION_LRT_OCCLUSION_ONLY = (1 << 0),
+ COLLECTION_LRT_EXCLUDE = (1 << 1),
+ COLLECTION_LRT_INTERSECTION_ONLY = (1 << 2),
+ COLLECTION_LRT_NO_INTERSECTION = (1 << 3),
+};
+
typedef struct Collection {
ID id;
@@ -63,8 +71,10 @@ typedef struct Collection {
/* Runtime-only, always cleared on file load. */
short tag;
+ /** Line Art engine specific */
+ short lineart_usage;
+
int16_t color_tag;
- char _pad[2];
/* Runtime. Cache of objects in this collection and all its
* children. This is created on demand when e.g. some physics
@@ -72,6 +82,9 @@ typedef struct Collection {
* collections due to memory usage reasons. */
ListBase object_cache;
+ /* Need this for line art sub-collection selections. */
+ ListBase object_cache_instanced;
+
/* Runtime. List of collections that are a parent of this
* datablock. */
ListBase parents;
@@ -89,6 +102,7 @@ enum {
COLLECTION_RESTRICT_RENDER = (1 << 3), /* Disable in renders. */
COLLECTION_HAS_OBJECT_CACHE = (1 << 4), /* Runtime: object_cache is populated. */
COLLECTION_IS_MASTER = (1 << 5), /* Is master collection embedded in the scene. */
+ COLLECTION_HAS_OBJECT_CACHE_INSTANCED = (1 << 6), /* for object_cache_instanced. */
};
/* Collection->tag */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 11d4ee1b2cd..baf2b2414fa 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -283,4 +283,17 @@
.colorband = NULL, \
}
+#define _DNA_DEFAULT_LineartGpencilModifierData \
+ { \
+ .line_types = LRT_EDGE_FLAG_ALL_TYPE, \
+ .thickness = 25, \
+ .opacity = 1.0f, \
+ .flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP | LRT_GPENCIL_SOFT_SELECTION, \
+ .crease_threshold = DEG2RAD(140.0f), \
+ .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_REMOVE_DOUBLES | LRT_ALLOW_OVERLAPPING_EDGES | LRT_ALLOW_CLIPPING_BOUNDARIES, \
+ .angle_splitting_threshold = DEG2RAD(60.0f), \
+ .chaining_geometry_threshold = 0.001f, \
+ .chaining_image_threshold = 0.001f, \
+ }
+
/* clang-format off */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index b2d62e0a5f6..a9262bf7ca4 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -53,6 +53,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_Time = 16,
eGpencilModifierType_Multiply = 17,
eGpencilModifierType_Texture = 18,
+ eGpencilModifierType_Lineart = 19,
/* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -809,6 +810,78 @@ typedef enum eTextureGpencil_Mode {
STROKE_AND_FILL = 2,
} eTextureGpencil_Mode;
+typedef enum eLineartGpencilModifierSource {
+ LRT_SOURCE_COLLECTION = 0,
+ LRT_SOURCE_OBJECT = 1,
+ LRT_SOURCE_SCENE = 2,
+} eLineartGpencilModifierSource;
+
+typedef enum eLineArtGPencilModifierFlags {
+ LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 0),
+ LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 1),
+ LRT_GPENCIL_SOFT_SELECTION = (1 << 2),
+ LRT_GPENCIL_IS_BAKED = (1 << 3),
+} eLineArtGPencilModifierFlags;
+
+typedef enum eLineartGpencilTransparencyFlags {
+ LRT_GPENCIL_TRANSPARENCY_ENABLE = (1 << 0),
+ /** Set to true means using "and" instead of "or" logic on mask bits. */
+ LRT_GPENCIL_TRANSPARENCY_MATCH = (1 << 1),
+} eLineartGpencilTransparencyFlags;
+
+typedef struct LineartGpencilModifierData {
+ GpencilModifierData modifier;
+
+ short line_types; /* line type enable flags, bits in eLineartEdgeFlag */
+
+ char source_type; /* Object or Collection, from eLineartGpencilModifierSource */
+
+ char use_multiple_levels;
+ short level_start;
+ short level_end;
+
+ struct Object *source_object;
+ struct Collection *source_collection;
+
+ struct Material *target_material;
+ char target_layer[64];
+
+ /** These two variables are to pass on vertex group information from mesh to strokes.
+ * vgname specifies which vertex groups our strokes from source_vertex_group will go to. */
+ char source_vertex_group[64];
+ char vgname[64];
+
+ float opacity;
+ short thickness;
+
+ unsigned char transparency_flags; /* eLineartGpencilTransparencyFlags */
+ unsigned char transparency_mask;
+
+ /** 0-1 range for cosine angle */
+ float crease_threshold;
+
+ /** 0-PI angle, for splitting strokes at sharp points */
+ float angle_splitting_threshold;
+
+ /* CPU mode */
+ float chaining_geometry_threshold;
+ float chaining_image_threshold;
+
+ float pre_sample_length;
+
+ /* Ported from SceneLineArt flags. */
+ int calculation_flags;
+
+ /* Additional Switches. */
+ int flags;
+
+ int _pad;
+
+ /* Runtime only. */
+ void *render_buffer;
+
+} LineartGpencilModifierData;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 9d969a29add..8facdca2f9c 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -34,6 +34,7 @@ extern "C" {
struct AnimData;
struct Curve;
struct MDeformVert;
+struct Curve;
#define GP_DEFAULT_PIX_FACTOR 1.0f
#define GP_DEFAULT_GRID_LINES 4
@@ -412,6 +413,8 @@ typedef enum eGPDframe_Flag {
GP_FRAME_PAINT = (1 << 0),
/* for editing in Action Editor */
GP_FRAME_SELECT = (1 << 1),
+ /* Line Art generation */
+ GP_FRAME_LRT_CLEARED = (1 << 2),
} eGPDframe_Flag;
/* ***************************************** */
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
new file mode 100644
index 00000000000..2eb36cfb9d3
--- /dev/null
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -0,0 +1,70 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DNA_LRT_TYPES_H__
+#define __DNA_LRT_TYPES_H__
+
+/** \file DNA_lineart_types.h
+ * \ingroup DNA
+ */
+
+#include "DNA_ID.h"
+#include "DNA_listBase.h"
+
+struct Object;
+struct Material;
+
+/* Notice that we need to have this file although no struct defines.
+ * Edge flags and usage flags are used by with scene/object/gpencil modifier bits, and those values
+ * needs to stay consistent throughout. */
+
+typedef enum eLineartMainFlags {
+ LRT_INTERSECTION_AS_CONTOUR = (1 << 0),
+ LRT_EVERYTHING_AS_CONTOUR = (1 << 1),
+ LRT_ALLOW_DUPLI_OBJECTS = (1 << 2),
+ LRT_ALLOW_OVERLAPPING_EDGES = (1 << 3),
+ LRT_ALLOW_CLIPPING_BOUNDARIES = (1 << 4),
+ LRT_REMOVE_DOUBLES = (1 << 5),
+} eLineartMainFlags;
+
+typedef enum eLineartEdgeFlag {
+ LRT_EDGE_FLAG_EDGE_MARK = (1 << 0),
+ LRT_EDGE_FLAG_CONTOUR = (1 << 1),
+ LRT_EDGE_FLAG_CREASE = (1 << 2),
+ LRT_EDGE_FLAG_MATERIAL = (1 << 3),
+ LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
+ /** floating edge, unimplemented yet */
+ LRT_EDGE_FLAG_FLOATING = (1 << 5),
+ /** also used as discarded line mark */
+ LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 6),
+ LRT_EDGE_FLAG_CLIPPED = (1 << 7),
+ /* Maxed out for 8 bits, DON'T ADD ANYMORE until improvements on the data structure. */
+} eLineartEdgeFlag;
+
+#define LRT_EDGE_FLAG_ALL_TYPE 0x3f
+
+#endif
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 884c2df6480..55d5ea202f7 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -145,6 +145,16 @@ typedef enum eMaterialGPencilStyle_Mode {
GP_MATERIAL_MODE_SQUARE = 2,
} eMaterialGPencilStyle_Mode;
+typedef struct MaterialLineArt {
+ int flags; /* eMaterialLineArtFlags */
+ unsigned char transparency_mask;
+ unsigned char _pad[3];
+} MaterialLineArt;
+
+typedef enum eMaterialLineArtFlags {
+ LRT_MATERIAL_TRANSPARENCY_ENABLED = (1 << 0),
+} eMaterialLineArtFlags;
+
typedef struct Material {
ID id;
/** Animation data (must be immediately after id for utilities to use it). */
@@ -210,6 +220,7 @@ typedef struct Material {
/** Grease pencil color. */
struct MaterialGPencilStyle *gp_style;
+ struct MaterialLineArt lineart;
} Material;
/* **************** MATERIAL ********************* */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index dbcb6ce45ea..368b1f93e4a 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -904,6 +904,7 @@ enum {
eBooleanModifierFlag_Self = (1 << 0),
eBooleanModifierFlag_Object = (1 << 1),
eBooleanModifierFlag_Collection = (1 << 2),
+ eBooleanModifierFlag_HoleTolerant = (1 << 3),
};
/* bm_flag only used when G_DEBUG. */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 8b0bc235861..acbe9da45fd 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -394,7 +394,6 @@ typedef struct bNodeLink {
bNodeSocket *fromsock, *tosock;
int flag;
- /* A runtime storage for automatically sorted links to multi-input sockets. */
int multi_input_socket_index;
} bNodeLink;
@@ -403,6 +402,7 @@ typedef struct bNodeLink {
#define NODE_LINK_VALID (1 << 1)
#define NODE_LINK_TEST (1 << 2) /* free test flag, undefined */
#define NODE_LINK_TEMP_HIGHLIGHT (1 << 3) /* Link is highlighted for picking. */
+#define NODE_LINK_MUTED (1 << 4) /* Link is muted. */
/* tree->edit_quality/tree->render_quality */
#define NTREE_QUALITY_HIGH 0
@@ -1067,14 +1067,39 @@ typedef struct CryptomatteEntry {
char _pad[4];
} CryptomatteEntry;
-typedef struct NodeCryptomatte {
+typedef struct CryptomatteLayer {
+ struct CryptomatteEntry *next, *prev;
+ char name[64];
+} CryptomatteLayer;
+
+typedef struct NodeCryptomatte_Runtime {
+ /* Contains `CryptomatteLayer`. */
+ ListBase layers;
+ /* Temp storage for the cryptomatte picker. */
float add[3];
float remove[3];
- char *matte_id DNA_DEPRECATED;
+} NodeCryptomatte_Runtime;
+
+typedef struct NodeCryptomatte {
+ /* iuser needs to be first element due to RNA limitations.
+ * When we define the ImageData properties, we can't define them from
+ * storage->iuser, so storage needs to be casted to ImageUser directly. */
+ ImageUser iuser;
+
/* Contains `CryptomatteEntry`. */
ListBase entries;
+
+ /* MAX_NAME */
+ char layer_name[64];
+ /* Stores `entries` as a string for opening in 2.80-2.91. */
+ char *matte_id;
+
+ /** Legacy attributes */
+ /* Number of input sockets. */
int num_inputs;
+
char _pad[4];
+ NodeCryptomatte_Runtime runtime;
} NodeCryptomatte;
typedef struct NodeDenoise {
@@ -1226,6 +1251,36 @@ typedef struct NodeAttributeSeparateXYZ {
uint8_t input_type;
} NodeAttributeSeparateXYZ;
+typedef struct NodeAttributeConvert {
+ /* CustomDataType. */
+ uint8_t data_type;
+ char _pad[1];
+ /* AttributeDomain. */
+ int16_t domain;
+} NodeAttributeConvert;
+
+typedef struct NodeGeometryMeshCircle {
+ /* GeometryNodeMeshCircleFillType. */
+ uint8_t fill_type;
+} NodeGeometryMeshCircle;
+
+typedef struct NodeGeometryMeshCylinder {
+ /* GeometryNodeMeshCircleFillType. */
+ uint8_t fill_type;
+} NodeGeometryMeshCylinder;
+
+typedef struct NodeGeometryMeshCone {
+ /* GeometryNodeMeshCircleFillType. */
+ uint8_t fill_type;
+} NodeGeometryMeshCone;
+
+typedef struct NodeGeometryMeshLine {
+ /* GeometryNodeMeshLineMode. */
+ uint8_t mode;
+ /* GeometryNodeMeshLineCountMode. */
+ uint8_t count_mode;
+} NodeGeometryMeshLine;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1702,6 +1757,22 @@ typedef enum GeometryNodePointsToVolumeResolutionMode {
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE = 1,
} GeometryNodePointsToVolumeResolutionMode;
+typedef enum GeometryNodeMeshCircleFillType {
+ GEO_NODE_MESH_CIRCLE_FILL_NONE = 0,
+ GEO_NODE_MESH_CIRCLE_FILL_NGON = 1,
+ GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN = 2,
+} GeometryNodeMeshCircleFillType;
+
+typedef enum GeometryNodeMeshLineMode {
+ GEO_NODE_MESH_LINE_MODE_END_POINTS = 0,
+ GEO_NODE_MESH_LINE_MODE_OFFSET = 1,
+} GeometryNodeMeshLineMode;
+
+typedef enum GeometryNodeMeshLineCountMode {
+ GEO_NODE_MESH_LINE_COUNT_TOTAL = 0,
+ GEO_NODE_MESH_LINE_COUNT_RESOLUTION = 1,
+} GeometryNodeMeshLineCountMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_defaults.h b/source/blender/makesdna/DNA_object_defaults.h
index 1bca572b963..d545b7912c0 100644
--- a/source/blender/makesdna/DNA_object_defaults.h
+++ b/source/blender/makesdna/DNA_object_defaults.h
@@ -66,6 +66,7 @@
.preview = NULL, \
.duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER, \
.pc_ids = {NULL, NULL}, \
+ .lineart = { .crease_threshold = DEG2RAD(140.0f) }, \
}
/** \} */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index f6372a0c240..fa4e3953f5b 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -26,6 +26,11 @@
#include "DNA_object_enums.h"
+#include "DNA_customdata_types.h"
+#include "DNA_defs.h"
+#include "DNA_lineart_types.h"
+#include "DNA_listBase.h"
+
#include "DNA_ID.h"
#include "DNA_action_types.h" /* bAnimVizSettings */
#include "DNA_customdata_types.h"
@@ -200,6 +205,27 @@ typedef struct Object_Runtime {
short _pad2[3];
} Object_Runtime;
+typedef struct ObjectLineArt {
+ short usage;
+ short flags;
+
+ /** if OBJECT_LRT_OWN_CREASE is set */
+ float crease_threshold;
+} ObjectLineArt;
+
+enum ObjectFeatureLine_Usage {
+ OBJECT_LRT_INHERENT = 0,
+ OBJECT_LRT_INCLUDE = (1 << 0),
+ OBJECT_LRT_OCCLUSION_ONLY = (1 << 1),
+ OBJECT_LRT_EXCLUDE = (1 << 2),
+ OBJECT_LRT_INTERSECTION_ONLY = (1 << 3),
+ OBJECT_LRT_NO_INTERSECTION = (1 << 4),
+};
+
+enum ObjectFeatureLine_Flags {
+ OBJECT_LRT_OWN_CREASE = (1 << 0),
+};
+
typedef struct Object {
ID id;
/** Animation data (must be immediately after id for utilities to use it). */
@@ -405,6 +431,8 @@ typedef struct Object {
struct PreviewImage *preview;
+ ObjectLineArt lineart;
+
/** Runtime evaluation data (keep last). */
Object_Runtime runtime;
} Object;
@@ -595,6 +623,9 @@ enum {
GP_EMPTY = 0,
GP_STROKE = 1,
GP_MONKEY = 2,
+ GP_LRT_SCENE = 3,
+ GP_LRT_OBJECT = 4,
+ GP_LRT_COLLECTION = 5,
};
/* boundtype */
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index 16129768b60..7a39e0caef3 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -73,6 +73,16 @@ enum {
/** #TreeStoreElem.types */
typedef enum eTreeStoreElemType {
+ /**
+ * If an element is of this type, `TreeStoreElem.id` points to a valid ID and the ID-type can be
+ * received through `TreeElement.idcode` (or `GS(TreeStoreElem.id->name)`). Note however that the
+ * types below may also have a valid ID pointer (see #TSE_IS_REAL_ID()).
+ *
+ * In cases where the type is still checked against "0" (even implicitly), please replace it with
+ * an explicit check against `TSE_SOME_ID`.
+ */
+ TSE_SOME_ID = 0,
+
TSE_NLA = 1, /* NO ID */
TSE_NLA_ACTION = 2,
TSE_DEFGROUP_BASE = 3,
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index 3e1b2ef56a1..1a2a8892e64 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -284,6 +284,15 @@
.count = 10, \
}
+#define _DNA_DEFAULTS_UnifiedPaintSettings \
+ { \
+ .size = 50, \
+ .unprojected_radius = 0.29, \
+ .alpha = 0.5f, \
+ .weight = 0.5f, \
+ .flag = UNIFIED_PAINT_SIZE | UNIFIED_PAINT_ALPHA, \
+ }
+
#define _DNA_DEFAULTS_ParticleEditSettings \
{ \
.flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY, \
@@ -346,6 +355,8 @@
\
.curve_paint_settings = _DNA_DEFAULTS_CurvePaintSettings, \
\
+ .unified_paint_settings = _DNA_DEFAULTS_UnifiedPaintSettings, \
+ \
.statvis = _DNA_DEFAULTS_MeshStatVis, \
\
.proportional_size = 1.0f, \
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index dc1775b09c6..755010cd8a5 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -66,6 +66,12 @@ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
/* Defined in `node_intern.h`. */
typedef struct SpaceNode_Runtime SpaceNode_Runtime;
+/* Defined in `file_intern.h`. */
+typedef struct SpaceFile_Runtime SpaceFile_Runtime;
+
+/* Defined in `spreadsheet_intern.hh`. */
+typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime;
+
/* -------------------------------------------------------------------- */
/** \name SpaceLink (Base)
* \{ */
@@ -222,6 +228,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_TOOL = 14,
BCONTEXT_SHADERFX = 15,
BCONTEXT_OUTPUT = 16,
+ BCONTEXT_COLLECTION = 17,
/* Keep last. */
BCONTEXT_TOT,
@@ -489,6 +496,7 @@ typedef enum eGraphEdit_Flag {
SIPO_NORMALIZE_FREEZE = (1 << 15),
/* show markers region */
SIPO_SHOW_MARKERS = (1 << 16),
+ SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17),
} eGraphEdit_Flag;
/* SpaceGraph.mode (Graph Editor Mode) */
@@ -639,6 +647,7 @@ typedef enum eSpaceSeq_Flag {
SEQ_SHOW_STRIP_NAME = (1 << 14),
SEQ_SHOW_STRIP_SOURCE = (1 << 15),
SEQ_SHOW_STRIP_DURATION = (1 << 16),
+ SEQ_USE_PROXIES = (1 << 17),
} eSpaceSeq_Flag;
/* SpaceSeq.view */
@@ -690,7 +699,7 @@ typedef enum eSpaceSeq_OverlayType {
* custom library. Otherwise idname is not used.
*/
typedef struct FileSelectAssetLibraryUID {
- short type;
+ short type; /* eFileAssetLibrary_Type */
char _pad[2];
/**
* If showing a custom asset library (#FILE_ASSET_LIBRARY_CUSTOM), this is the index of the
@@ -846,6 +855,8 @@ typedef struct SpaceFile {
short recentnr, bookmarknr;
short systemnr, system_bookmarknr;
+
+ SpaceFile_Runtime *runtime;
} SpaceFile;
/* SpaceFile.browse_mode (File Space Browsing Mode) */
@@ -1835,6 +1846,47 @@ typedef struct SpaceStatusBar {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Spreadsheet
+ * \{ */
+
+typedef struct SpaceSpreadsheet {
+ SpaceLink *next, *prev;
+ /** Storage of regions for inactive spaces. */
+ ListBase regionbase;
+ char spacetype;
+ char link_flag;
+ char _pad0[6];
+ /* End 'SpaceLink' header. */
+
+ struct ID *pinned_id;
+
+ /* eSpaceSpreadsheet_FilterFlag. */
+ uint8_t filter_flag;
+
+ /* #GeometryComponentType. */
+ uint8_t geometry_component_type;
+ /* #AttributeDomain. */
+ uint8_t attribute_domain;
+ /* eSpaceSpreadsheet_ObjectContext. */
+ uint8_t object_eval_state;
+
+ char _pad1[4];
+
+ SpaceSpreadsheet_Runtime *runtime;
+} SpaceSpreadsheet;
+
+/** \} */
+
+typedef enum eSpaceSpreadsheet_FilterFlag {
+ SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
+} eSpaceSpreadsheet_FilterFlag;
+
+typedef enum eSpaceSpreadsheet_ObjectEvalState {
+ SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0,
+ SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
+} eSpaceSpreadsheet_Context;
+
+/* -------------------------------------------------------------------- */
/** \name Space Defines (eSpace_Type)
* \{ */
@@ -1871,8 +1923,9 @@ typedef enum eSpace_Type {
SPACE_CLIP = 20,
SPACE_TOPBAR = 21,
SPACE_STATUSBAR = 22,
+ SPACE_SPREADSHEET = 23
-#define SPACE_TYPE_LAST SPACE_STATUSBAR
+#define SPACE_TYPE_LAST SPACE_SPREADSHEET
} eSpace_Type;
/* use for function args */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index d304641e112..7c92317b1b2 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -492,6 +492,7 @@ typedef struct bTheme {
ThemeSpace space_clip;
ThemeSpace space_topbar;
ThemeSpace space_statusbar;
+ ThemeSpace space_spreadsheet;
/* 20 sets of bone colors for this theme */
ThemeWireColor tarm[20];
@@ -507,7 +508,7 @@ typedef struct bTheme {
#define UI_THEMESPACE_START(btheme) \
(CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties))
#define UI_THEMESPACE_END(btheme) \
- (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_statusbar) + 1))
+ (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_spreadsheet) + 1))
typedef struct bAddon {
struct bAddon *next, *prev;
@@ -634,6 +635,7 @@ typedef struct UserDef_FileSpaceData {
typedef struct UserDef_Experimental {
/* Debug options, always available. */
char use_undo_legacy;
+ char no_override_auto_resync;
char use_cycles_debug;
char SANITIZE_AFTER_HERE;
/* The following options are automatically sanitized (set to 0)
@@ -644,7 +646,7 @@ typedef struct UserDef_Experimental {
char use_switch_object_operator;
char use_sculpt_tools_tilt;
char use_asset_browser;
- char _pad[7];
+ char _pad[6];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
@@ -919,7 +921,7 @@ typedef struct UserDef {
int sequencer_disk_cache_compression; /* eUserpref_DiskCacheCompression */
int sequencer_disk_cache_size_limit;
short sequencer_disk_cache_flag;
- char _pad5[2];
+ short sequencer_proxy_setup; /* eUserpref_SeqProxySetup */
float collection_instance_empty_size;
char _pad10[3];
@@ -1384,6 +1386,11 @@ typedef enum eUserpref_DiskCacheCompression {
USER_SEQ_DISK_CACHE_COMPRESSION_HIGH = 2,
} eUserpref_DiskCacheCompression;
+typedef enum eUserpref_SeqProxySetup {
+ USER_SEQ_PROXY_SETUP_MANUAL = 0,
+ USER_SEQ_PROXY_SETUP_AUTOMATIC = 1,
+} eUserpref_SeqProxySetup;
+
/* Locale Ids. Auto will try to get local from OS. Our default is English though. */
/** #UserDef.language */
enum {
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 1635aa7646b..68d69a671ba 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -154,8 +154,8 @@ typedef struct wmWindowManager {
/** Operator registry. */
ListBase operators;
- /** Refresh/redraw wmNotifier structs. */
- ListBase queue;
+ /** Refresh/redraw #wmNotifier structs. */
+ ListBase notifier_queue;
/** Information and error reports. */
struct ReportList reports;
@@ -251,13 +251,14 @@ typedef struct wmWindow {
struct bScreen *screen DNA_DEPRECATED;
+ /** Winid also in screens, is for retrieving this window after read. */
+ int winid;
/** Window coords. */
short posx, posy, sizex, sizey;
/** Borderless, full. */
char windowstate;
/** Set to 1 if an active window, for quick rejects. */
char active;
- char _pad0[4];
/** Current mouse cursor type. */
short cursor;
/** Previous cursor when setting modal one. */
@@ -271,16 +272,22 @@ typedef struct wmWindow {
char addmousemove;
char tag_cursor_refresh;
- /** Winid also in screens, is for retrieving this window after read. */
- int winid;
+ /* Track the state of the event queue,
+ * these store the state that needs to be kept between handling events in the queue. */
+ /** Enable when #KM_PRESS events are not handled (keyboard/mouse-buttons only). */
+ char event_queue_check_click;
+ /** Enable when #KM_PRESS events are not handled (keyboard/mouse-buttons only). */
+ char event_queue_check_drag;
+
+ char _pad0[2];
/** Internal, lock pie creation from this event until released. */
- short lock_pie_event;
+ short pie_event_type_lock;
/**
* Exception to the above rule for nested pies, store last pie event for operators
* that spawn a new pie right after destruction of last pie.
*/
- short last_pie_event;
+ short pie_event_type_last;
/** Storage for event system. */
struct wmEvent *eventstate;
@@ -292,8 +299,8 @@ typedef struct wmWindow {
* Currently WIN32, runtime-only data. */
struct wmIMEData *ime_data;
- /** All events (ghost level events were handled). */
- ListBase queue;
+ /** All events #wmEvent (ghost level events were handled). */
+ ListBase event_queue;
/** Window+screen handlers, handled last. */
ListBase handlers;
/** Priority handlers, handled first. */
@@ -355,7 +362,7 @@ typedef struct wmKeyMapItem {
short val;
/** Oskey is apple or windowskey, value denotes order of pressed. */
short shift, ctrl, alt, oskey;
- /** Rawkey modifier. */
+ /** Raw-key modifier. */
short keymodifier;
/* flag: inactive, expanded */
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 3e4d5d87fb0..95272fb7804 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -315,6 +315,7 @@ SDNA_DEFAULT_DECL_STRUCT(TextureGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(ThickGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(TimeGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(TintGpencilModifierData);
+SDNA_DEFAULT_DECL_STRUCT(LineartGpencilModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@@ -425,6 +426,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(ToolSettings),
SDNA_DEFAULT_DECL_EX(CurvePaintSettings, ToolSettings.curve_paint_settings),
SDNA_DEFAULT_DECL_EX(ImagePaintSettings, ToolSettings.imapaint),
+ SDNA_DEFAULT_DECL_EX(UnifiedPaintSettings, ToolSettings.unified_paint_settings),
SDNA_DEFAULT_DECL_EX(ParticleEditSettings, ToolSettings.particle),
SDNA_DEFAULT_DECL_EX(ParticleBrushData, ToolSettings.particle.brush[0]),
SDNA_DEFAULT_DECL_EX(MeshStatVis, ToolSettings.statvis),
@@ -538,6 +540,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(ThickGpencilModifierData),
SDNA_DEFAULT_DECL(TimeGpencilModifierData),
SDNA_DEFAULT_DECL(TintGpencilModifierData),
+ SDNA_DEFAULT_DECL(LineartGpencilModifierData),
};
#undef SDNA_DEFAULT_DECL
#undef SDNA_DEFAULT_DECL_EX
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 7624649bf78..26fc56cfa1d 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -84,6 +84,7 @@ static const char *includefiles[] = {
"DNA_mesh_types.h",
"DNA_meshdata_types.h",
"DNA_modifier_types.h",
+ "DNA_lineart_types.h",
"DNA_lattice_types.h",
"DNA_object_types.h",
"DNA_object_force_types.h",
@@ -1558,6 +1559,7 @@ int main(int argc, char **argv)
#include "DNA_layer_types.h"
#include "DNA_light_types.h"
#include "DNA_lightprobe_types.h"
+#include "DNA_lineart_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_listBase.h"
#include "DNA_mask_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index eecac8ca19e..ba67cedfdbe 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -142,6 +142,8 @@ extern StructRNA RNA_CompositorNodeCombYUVA;
extern StructRNA RNA_CompositorNodeComposite;
extern StructRNA RNA_CompositorNodeCornerPin;
extern StructRNA RNA_CompositorNodeCrop;
+extern StructRNA RNA_CompositorNodeCryptomatte;
+extern StructRNA RNA_CompositorNodeCryptomatteV2;
extern StructRNA RNA_CompositorNodeCurveRGB;
extern StructRNA RNA_CompositorNodeCurveVec;
extern StructRNA RNA_CompositorNodeDBlur;
@@ -454,6 +456,7 @@ extern StructRNA RNA_NormalEditModifier;
extern StructRNA RNA_Object;
extern StructRNA RNA_ObjectBase;
extern StructRNA RNA_ObjectDisplay;
+extern StructRNA RNA_ObjectLineArt;
extern StructRNA RNA_OceanModifier;
extern StructRNA RNA_OceanTexData;
extern StructRNA RNA_OffsetGpencilModifier;
@@ -601,6 +604,7 @@ extern StructRNA RNA_SpaceOutliner;
extern StructRNA RNA_SpacePreferences;
extern StructRNA RNA_SpaceProperties;
extern StructRNA RNA_SpaceSequenceEditor;
+extern StructRNA RNA_SpaceSpreadsheet;
extern StructRNA RNA_SpaceTextEditor;
extern StructRNA RNA_SpaceUVEditor;
extern StructRNA RNA_SpaceView3D;
@@ -1020,7 +1024,6 @@ int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
-void *RNA_property_enum_py_data_get(PropertyRNA *prop);
int RNA_property_enum_step(
const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
@@ -1511,11 +1514,21 @@ bool RNA_struct_override_store(struct Main *bmain,
PointerRNA *ptr_storage,
struct IDOverrideLibrary *override);
+typedef enum eRNAOverrideApplyFlag {
+ RNA_OVERRIDE_APPLY_FLAG_NOP = 0,
+ /**
+ * Hack to work around/fix older broken overrides: Do not apply override operations affecting ID
+ * pointers properties, unless the destination original value (the one being overridden) is NULL.
+ */
+ RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS = 1 << 0,
+} eRNAOverrideApplyFlag;
+
void RNA_struct_override_apply(struct Main *bmain,
struct PointerRNA *ptr_dst,
struct PointerRNA *ptr_src,
struct PointerRNA *ptr_storage,
- struct IDOverrideLibrary *override);
+ struct IDOverrideLibrary *override,
+ const eRNAOverrideApplyFlag flag);
struct IDOverrideLibraryProperty *RNA_property_override_property_find(struct Main *bmain,
PointerRNA *ptr,
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index c12426ffcd0..bc1a8f52b8d 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -421,7 +421,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *length,
const char *set);
void RNA_def_property_pointer_funcs(
- PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll);
+ PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll);
void RNA_def_property_collection_funcs(PropertyRNA *prop,
const char *begin,
const char *next,
@@ -465,8 +465,6 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc);
-void RNA_def_property_enum_py_data(PropertyRNA *prop, void *py_data);
-
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context);
/* Function */
@@ -507,6 +505,9 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
void RNA_def_property_free_pointers(PropertyRNA *prop);
int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *identifier);
+void RNA_def_property_free_pointers_set_py_data_callback(
+ void (*py_data_clear_fn)(PropertyRNA *prop));
+
/* utilities */
const char *RNA_property_typename(PropertyType type);
#define IS_DNATYPE_FLOAT_COMPAT(_str) (strcmp(_str, "float") == 0 || strcmp(_str, "double") == 0)
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 94cfd8464ae..4fafa356879 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -298,10 +298,22 @@ if(WITH_OPENAL)
add_definitions(-DWITH_OPENAL)
endif()
+if(WITH_COREAUDIO)
+ add_definitions(-DWITH_COREAUDIO)
+endif()
+
if(WITH_JACK)
add_definitions(-DWITH_JACK)
endif()
+if(WITH_PULSEAUDIO)
+ add_definitions(-DWITH_PULSEAUDIO)
+endif()
+
+if(WITH_WASAPI)
+ add_definitions(-DWITH_WASAPI)
+endif()
+
if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
@@ -443,6 +455,7 @@ set(LIB
bf_editor_undo
)
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_rna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index bec3db10905..6940e475f39 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3671,7 +3671,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
}
}
else {
- if (!defaultfound && !(eprop->itemf && eprop->item == DummyRNA_NULL_items)) {
+ if (!defaultfound && !(eprop->item_fn && eprop->item == DummyRNA_NULL_items)) {
CLOG_ERROR(&LOG,
"%s%s.%s, enum default is not in items.",
srna->identifier,
@@ -3989,10 +3989,10 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
fprintf(f,
- "\t%s, %s, %s, %s, %s, NULL, ",
+ "\t%s, %s, %s, %s, %s, ",
rna_function_string(eprop->get),
rna_function_string(eprop->set),
- rna_function_string(eprop->itemf),
+ rna_function_string(eprop->item_fn),
rna_function_string(eprop->get_ex),
rna_function_string(eprop->set_ex));
if (eprop->item) {
@@ -4010,7 +4010,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
"\t%s, %s, %s, %s,",
rna_function_string(pprop->get),
rna_function_string(pprop->set),
- rna_function_string(pprop->typef),
+ rna_function_string(pprop->type_fn),
rna_function_string(pprop->poll));
if (pprop->type) {
fprintf(f, "&RNA_%s\n", (const char *)pprop->type);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index fd19352a9a5..6e2005b7314 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -528,6 +528,9 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
if (newid != NULL) {
id_us_min(newid);
}
+
+ WM_main_add_notifier(NC_ID | NA_ADDED, NULL);
+
return newid;
}
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index c5dd516d16e..f94dc38ddfe 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1571,8 +1571,8 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->typef) {
- return pprop->typef(ptr);
+ if (pprop->type_fn) {
+ return pprop->type_fn(ptr);
}
if (pprop->type) {
return pprop->type;
@@ -1623,14 +1623,14 @@ void RNA_property_enum_items_ex(bContext *C,
*r_free = false;
- if (!use_static && eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
+ if (!use_static && eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
const EnumPropertyItem *item;
if (prop->flag & PROP_ENUM_NO_CONTEXT) {
- item = eprop->itemf(NULL, ptr, prop, r_free);
+ item = eprop->item_fn(NULL, ptr, prop, r_free);
}
else {
- item = eprop->itemf(C, ptr, prop, r_free);
+ item = eprop->item_fn(C, ptr, prop, r_free);
}
/* any callbacks returning NULL should be fixed */
@@ -1753,16 +1753,16 @@ void RNA_property_enum_items_gettexted_all(bContext *C,
*r_totitem = eprop->totitem;
}
- if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
+ if (eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
const EnumPropertyItem *item;
int i;
bool free = false;
if (prop->flag & PROP_ENUM_NO_CONTEXT) {
- item = eprop->itemf(NULL, ptr, prop, &free);
+ item = eprop->item_fn(NULL, ptr, prop, &free);
}
else {
- item = eprop->itemf(C, ptr, prop, &free);
+ item = eprop->item_fn(C, ptr, prop, &free);
}
/* any callbacks returning NULL should be fixed */
@@ -3598,15 +3598,6 @@ int RNA_property_enum_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
return eprop->defaultvalue;
}
-void *RNA_property_enum_py_data_get(PropertyRNA *prop)
-{
- EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
-
- BLI_assert(RNA_property_type(prop) == PROP_ENUM);
-
- return eprop->py_data;
-}
-
/**
* Get the value of the item that is \a step items away from \a from_value.
*
@@ -3662,8 +3653,8 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
}
/* for groups, data is idprop itself */
- if (pprop->typef) {
- return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop);
+ if (pprop->type_fn) {
+ return rna_pointer_inherit_refine(ptr, pprop->type_fn(ptr), idprop);
}
return rna_pointer_inherit_refine(ptr, pprop->type, idprop);
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index d6305388cf9..d286d101b81 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -20,6 +20,8 @@
#include <string.h>
+#include <CLG_log.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
@@ -53,11 +55,13 @@
#include "rna_access_internal.h"
#include "rna_internal.h"
+static CLG_LogRef LOG = {"rna.access_compare_override"};
+
/**
* Find the actual ID owner of the given \a ptr #PointerRNA, in override sense, and generate the
* full rna path from it to given \a prop #PropertyRNA if \a rna_path is given.
*
- * \note this is slightly different than 'generic' RNA 'id owner' as returned by
+ * \note This is slightly different than 'generic' RNA 'id owner' as returned by
* #RNA_find_real_ID_and_path, since in overrides we also consider shape keys as embedded data, not
* only root node trees and master collections.
*/
@@ -100,10 +104,6 @@ static ID *rna_property_override_property_real_id_owner(Main *bmain,
}
}
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
- return NULL;
- }
-
if (r_rna_path == NULL) {
return owner_id;
}
@@ -411,12 +411,11 @@ static int rna_property_override_diff(Main *bmain,
}
if (override_diff == NULL) {
-#ifndef NDEBUG
- printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
- rna_path ? rna_path : prop_a->identifier,
- !prop_a->is_idprop,
- !prop_b->is_idprop);
-#endif
+ CLOG_ERROR(&LOG,
+ "'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d)",
+ rna_path ? rna_path : prop_a->identifier,
+ !prop_a->is_idprop,
+ !prop_b->is_idprop);
BLI_assert(0);
return 1;
}
@@ -501,12 +500,11 @@ static bool rna_property_override_operation_store(Main *bmain,
}
if (override_store == NULL) {
-#ifndef NDEBUG
- printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n",
- op->rna_path,
- prop_local->magic == RNA_MAGIC,
- prop_reference->magic == RNA_MAGIC);
-#endif
+ CLOG_ERROR(&LOG,
+ "'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d)",
+ op->rna_path,
+ prop_local->magic == RNA_MAGIC,
+ prop_reference->magic == RNA_MAGIC);
BLI_assert(0);
return changed;
}
@@ -590,12 +588,12 @@ static bool rna_property_override_operation_apply(Main *bmain,
}
if (override_apply == NULL) {
-#ifndef NDEBUG
- printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n",
- prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
- prop_dst->magic == RNA_MAGIC,
- prop_src->magic == RNA_MAGIC);
-#endif
+ CLOG_ERROR(&LOG,
+ "'%s' gives unmatching or NULL RNA apply callbacks, should not happen (%d vs. %d)",
+ prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name :
+ prop_dst->identifier,
+ prop_dst->magic == RNA_MAGIC,
+ prop_src->magic == RNA_MAGIC);
BLI_assert(0);
return false;
}
@@ -788,7 +786,7 @@ bool RNA_struct_override_matches(Main *bmain,
continue;
}
- // printf("Override Checking %s\n", rna_path);
+ CLOG_INFO(&LOG, 5, "Override Checking %s\n", rna_path);
IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path);
if (ignore_overridden && op != NULL) {
@@ -990,11 +988,9 @@ static void rna_property_override_apply_ex(Main *bmain,
if (!do_insert != !ELEM(opop->operation,
IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) {
-#ifndef NDEBUG
if (!do_insert) {
- printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path);
+ CLOG_INFO(&LOG, 5, "Skipping insert override operations in first pass (%s)", op->rna_path);
}
-#endif
continue;
}
@@ -1078,22 +1074,25 @@ static void rna_property_override_apply_ex(Main *bmain,
ptr_item_src = &private_ptr_item_src;
ptr_item_storage = &private_ptr_item_storage;
-#ifndef NDEBUG
if (ptr_item_dst->type == NULL) {
- printf("Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'\n",
- opop->subitem_reference_name,
- opop->subitem_reference_index,
- op->rna_path,
- ptr_dst->owner_id->name);
+ CLOG_INFO(
+ &LOG,
+ 2,
+ "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
+ opop->subitem_reference_name,
+ opop->subitem_reference_index,
+ op->rna_path,
+ ptr_dst->owner_id->name);
}
if (ptr_item_src->type == NULL) {
- printf("Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'\n",
- opop->subitem_local_name,
- opop->subitem_local_index,
- op->rna_path,
- ptr_src->owner_id->name);
+ CLOG_INFO(&LOG,
+ 2,
+ "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
+ opop->subitem_local_name,
+ opop->subitem_local_index,
+ op->rna_path,
+ ptr_src->owner_id->name);
}
-#endif
}
if (!rna_property_override_operation_apply(bmain,
@@ -1107,9 +1106,11 @@ static void rna_property_override_apply_ex(Main *bmain,
ptr_item_src,
ptr_item_storage,
opop)) {
- printf("Failed to apply '%s' override operation on %s\n",
- op->rna_path,
- ptr_src->owner_id->name);
+ CLOG_INFO(&LOG,
+ 4,
+ "Failed to apply '%s' override operation on %s\n",
+ op->rna_path,
+ ptr_src->owner_id->name);
}
}
}
@@ -1122,7 +1123,8 @@ void RNA_struct_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
PointerRNA *ptr_storage,
- IDOverrideLibrary *override)
+ IDOverrideLibrary *override,
+ const eRNAOverrideApplyFlag flag)
{
#ifdef DEBUG_OVERRIDE_TIMEIT
TIMEIT_START_AVERAGED(RNA_struct_override_apply);
@@ -1153,6 +1155,72 @@ void RNA_struct_override_apply(Main *bmain,
ptr_storage, op->rna_path, &data_storage, &prop_storage, &data_item_storage);
}
+ /* Check if an overridden ID pointer supposed to be in sync with linked data gets out of
+ * sync. */
+ if ((ptr_dst->owner_id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0 &&
+ op->rna_prop_type == PROP_POINTER &&
+ (((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag &
+ IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
+ BLI_assert(ptr_src->owner_id ==
+ rna_property_override_property_real_id_owner(bmain, &data_src, NULL, NULL));
+ BLI_assert(ptr_dst->owner_id ==
+ rna_property_override_property_real_id_owner(bmain, &data_dst, NULL, NULL));
+
+ PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
+ PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst);
+ ID *id_src = rna_property_override_property_real_id_owner(
+ bmain, &prop_ptr_src, NULL, NULL);
+ ID *id_dst = rna_property_override_property_real_id_owner(
+ bmain, &prop_ptr_dst, NULL, NULL);
+
+ BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src));
+
+ if (/* We might be in a case where id_dst has already been processed and its usages
+ * remapped to its new local override. In that case overrides and linked data are
+ * always properly matching. */
+ id_src != id_dst &&
+ /* If one of the pointers is NULL and not the other, or if linked reference ID of
+ * `id_src` is not `id_dst`, we are in a non-matching case. */
+ (ELEM(NULL, id_src, id_dst) || id_src->override_library->reference != id_dst)) {
+ ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ CLOG_INFO(
+ &LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name);
+ }
+ }
+
+ /* Workaround for older broken overrides, we then assume that non-matching ID pointers
+ * override operations that replace a non-NULL value are 'mistakes', and ignore (do not
+ * apply) them. */
+ if ((flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) != 0 &&
+ op->rna_prop_type == PROP_POINTER &&
+ (((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag &
+ IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
+ BLI_assert(ptr_src->owner_id ==
+ rna_property_override_property_real_id_owner(bmain, &data_src, NULL, NULL));
+ BLI_assert(ptr_dst->owner_id ==
+ rna_property_override_property_real_id_owner(bmain, &data_dst, NULL, NULL));
+
+ PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst);
+ if (prop_ptr_dst.type != NULL && RNA_struct_is_ID(prop_ptr_dst.type)) {
+#ifndef NDEBUG
+ PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
+ BLI_assert(prop_ptr_src.type == NULL || RNA_struct_is_ID(prop_ptr_src.type));
+#endif
+ ID *id_dst = rna_property_override_property_real_id_owner(
+ bmain, &prop_ptr_dst, NULL, NULL);
+
+ if (id_dst != NULL) {
+ CLOG_INFO(&LOG,
+ 4,
+ "%s: Ignoring local override on ID pointer property '%s', as requested by "
+ "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
+ ptr_dst->owner_id->name,
+ op->rna_path);
+ continue;
+ }
+ }
+ }
+
rna_property_override_apply_ex(bmain,
&data_dst,
&data_src,
@@ -1166,17 +1234,16 @@ void RNA_struct_override_apply(Main *bmain,
op,
do_insert);
}
-#ifndef NDEBUG
else {
- printf(
- "Failed to apply library override operation to '%s.%s' "
- "(could not resolve some properties, local: %d, override: %d)\n",
- ((ID *)ptr_src->owner_id)->name,
- op->rna_path,
- RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
- RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
+ CLOG_INFO(&LOG,
+ 4,
+ "Failed to apply library override operation to '%s.%s' "
+ "(could not resolve some properties, local: %d, override: %d)",
+ ((ID *)ptr_src->owner_id)->name,
+ op->rna_path,
+ RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
+ RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
}
-#endif
}
}
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 06ab62aa1ec..554f04ca23c 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -966,10 +966,11 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_DRAWWIRE);
- RNA_def_property_ui_text(prop,
- "Display Wire",
- "Bone is always displayed in wireframe regardless of viewport shading mode "
- "(useful for non-obstructive custom bone shapes)");
+ RNA_def_property_ui_text(
+ prop,
+ "Display Wire",
+ "Bone is always displayed in wireframe regardless of viewport shading mode "
+ "(useful for non-obstructive custom bone shapes)");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
/* XXX: use_cyclic_offset is deprecated in 2.5. May/may not return */
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 8936a0b1b45..e7daa55af6c 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1887,7 +1887,8 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_lasso", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_BRUSH_DISSABLE_LASSO);
- RNA_def_property_ui_text(prop, "Show Lasso", "Do not display fill color while drawing the stroke");
+ RNA_def_property_ui_text(
+ prop, "Show Lasso", "Do not display fill color while drawing the stroke");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
prop = RNA_def_property(srna, "use_occlude_eraser", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
index 20a455f5312..643503e52fa 100644
--- a/source/blender/makesrna/intern/rna_collection.c
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -22,6 +22,8 @@
#include "DNA_collection_types.h"
+#include "DNA_lineart_types.h"
+
#include "BLI_utildefines.h"
#include "RNA_define.h"
@@ -517,6 +519,35 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
+ static const EnumPropertyItem rna_collection_lineart_usage[] = {
+ {COLLECTION_LRT_INCLUDE,
+ "INCLUDE",
+ 0,
+ "Include",
+ "Generate feature lines for this collection"},
+ {COLLECTION_LRT_OCCLUSION_ONLY,
+ "OCCLUSION_ONLY",
+ 0,
+ "Occlusion Only",
+ "Only use the collection to produce occlusion"},
+ {COLLECTION_LRT_EXCLUDE, "EXCLUDE", 0, "Exclude", "Don't use this collection in line art"},
+ {COLLECTION_LRT_INTERSECTION_ONLY,
+ "INTERSECTION_ONLY",
+ 0,
+ "Intersection Only",
+ "Only generate intersection lines for this collection"},
+ {COLLECTION_LRT_NO_INTERSECTION,
+ "NO_INTERSECTION",
+ 0,
+ "No Intersection",
+ "Include this collection but do not generate intersection lines"},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "lineart_usage", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_collection_lineart_usage);
+ RNA_def_property_ui_text(prop, "Usage", "How to use this collection in line art");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
prop = RNA_def_property(srna, "color_tag", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_tag");
RNA_def_property_enum_funcs(
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index df3bd0cca29..019823a7de3 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3267,7 +3267,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop,
eprop->set = (PropEnumSetFunc)set;
}
if (item) {
- eprop->itemf = (PropEnumItemFunc)item;
+ eprop->item_fn = (PropEnumItemFunc)item;
}
break;
}
@@ -3292,7 +3292,7 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
eprop->set_ex = setfunc;
}
if (itemfunc) {
- eprop->itemf = itemfunc;
+ eprop->item_fn = itemfunc;
}
if (getfunc || setfunc) {
@@ -3305,12 +3305,6 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
}
}
-void RNA_def_property_enum_py_data(PropertyRNA *prop, void *py_data)
-{
- EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
- eprop->py_data = py_data;
-}
-
void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *get,
const char *length,
@@ -3373,7 +3367,7 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
}
void RNA_def_property_pointer_funcs(
- PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll)
+ PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll)
{
StructRNA *srna = DefRNA.laststruct;
@@ -3392,8 +3386,8 @@ void RNA_def_property_pointer_funcs(
if (set) {
pprop->set = (PropPointerSetFunc)set;
}
- if (typef) {
- pprop->typef = (PropPointerTypeFunc)typef;
+ if (type_fn) {
+ pprop->type_fn = (PropPointerTypeFunc)type_fn;
}
if (poll) {
pprop->poll = (PropPointerPollFunc)poll;
@@ -3821,7 +3815,7 @@ PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
- eprop->itemf = itemfunc;
+ eprop->item_fn = itemfunc;
}
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_,
@@ -4632,11 +4626,28 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
prop->flag_internal |= PROP_INTERN_FREE_POINTERS;
}
+static void (*g_py_data_clear_fn)(PropertyRNA *prop) = NULL;
+
+/**
+ * Set the callback used to decrement the user count of a property.
+ *
+ * This function is called when freeing each dynamically defined property.
+ */
+void RNA_def_property_free_pointers_set_py_data_callback(
+ void (*py_data_clear_fn)(PropertyRNA *prop))
+{
+ g_py_data_clear_fn = py_data_clear_fn;
+}
+
void RNA_def_property_free_pointers(PropertyRNA *prop)
{
if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) {
int a;
+ if (g_py_data_clear_fn) {
+ g_py_data_clear_fn(prop);
+ }
+
if (prop->identifier) {
MEM_freeN((void *)prop->identifier);
}
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 71d5a53adb2..0fe0ad26cca 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -88,6 +88,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_SUBSURF,
"Subdivide",
"Subdivide stroke adding more control points"},
+ {eGpencilModifierType_Lineart,
+ "GP_LINEART",
+ ICON_MOD_EDGESPLIT, /* TODO: Use a proper icon. */
+ "Line Art",
+ "Generate line art strokes from selected source"},
{0, "", 0, N_("Deform"), ""},
{eGpencilModifierType_Armature,
"GP_ARMATURE",
@@ -241,6 +246,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_MultiplyGpencilModifier;
case eGpencilModifierType_Texture:
return &RNA_TextureGpencilModifier;
+ case eGpencilModifierType_Lineart:
+ return &RNA_LineartGpencilModifier;
/* Default */
case eGpencilModifierType_None:
case NUM_GREASEPENCIL_MODIFIER_TYPES:
@@ -311,6 +318,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Armature, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Texture, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Tint, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Lineart, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -2305,6 +2313,284 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
}
+static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem modifier_lineart_source_type[] = {
+ {LRT_SOURCE_COLLECTION, "COLLECTION", 0, "Collection", ""},
+ {LRT_SOURCE_OBJECT, "OBJECT", 0, "Object", ""},
+ {LRT_SOURCE_SCENE, "SCENE", 0, "Scene", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "LineartGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(
+ srna, "Line Art Modifier", "Generate line art strokes from selected source");
+ RNA_def_struct_sdna(srna, "LineartGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_EDGESPLIT);
+
+ prop = RNA_def_property(srna, "fuzzy_intersections", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_INTERSECTION_AS_CONTOUR);
+ RNA_def_property_ui_text(prop,
+ "Intersection With Contour",
+ "Treat intersection and contour lines as if they were the same type so "
+ "they can be chained together");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fuzzy_everything", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_EVERYTHING_AS_CONTOUR);
+ RNA_def_property_ui_text(
+ prop, "All Lines", "Treat all lines as the same line type so they can be chained together");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "allow_duplication", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_DUPLI_OBJECTS);
+ RNA_def_property_ui_text(
+ prop,
+ "Instanced Objects",
+ "Allow particle objects and face/vertiex duplication to show in line art");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "allow_overlapping_edges", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_OVERLAPPING_EDGES);
+ RNA_def_property_ui_text(
+ prop,
+ "Handle Overlapping Edges",
+ "Allow edges in the same location (i.e. from edge split) to show properly. May run slower");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "allow_clipping_boundaries", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_CLIPPING_BOUNDARIES);
+ RNA_def_property_ui_text(
+ prop, "Clipping Boundaries", "Allow lines on near/far clipping plane to be shown");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "crease_threshold", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0, DEG2RAD(180.0f));
+ RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(180.0f), 0.01f, 1);
+ RNA_def_property_ui_text(
+ prop, "Crease Threshold", "Angles smaller than this will be treated as creases");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "angle_splitting_threshold", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_ui_text(
+ prop, "Angle Splitting", "Angle in screen space below which a stroke is split in two");
+ /* Don't allow value very close to PI, or we get a lot of small segments.*/
+ RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(179.5f), 0.01f, 1);
+ RNA_def_property_range(prop, 0.0f, DEG2RAD(180.0f));
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "remove_doubles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_REMOVE_DOUBLES);
+ RNA_def_property_ui_text(
+ prop, "Remove Doubles", "Remove doubles from the source geometry before generating stokes");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "chaining_geometry_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_ui_text(prop,
+ "Geometry Threshold",
+ "Segments with a geometric distance between them lower than this "
+ "will be chained together");
+ RNA_def_property_ui_range(prop, 0.0f, 0.5f, 0.001f, 3);
+ RNA_def_property_range(prop, 0.0f, 0.5f);
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_ui_text(
+ prop,
+ "Image Threshold",
+ "Segments with an image distance smaller than this will be chained together");
+ RNA_def_property_ui_range(prop, 0.0f, 0.3f, 0.001f, 4);
+ RNA_def_property_range(prop, 0.0f, 0.3f);
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "source_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_lineart_source_type);
+ RNA_def_property_ui_text(prop, "Source Type", "Line art stroke source type");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "source_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(
+ prop, "Source Object", "Source object that this modifier uses data from");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "source_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(
+ prop, "Source Collection", "Source collection that this modifier uses data from");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ /* types */
+ prop = RNA_def_property(srna, "use_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "line_types", LRT_EDGE_FLAG_CONTOUR);
+ RNA_def_property_ui_text(prop, "Use Contour", "Generate strokes from contours lines");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "line_types", LRT_EDGE_FLAG_CREASE);
+ RNA_def_property_ui_text(prop, "Use Crease", "Generate strokes from creased edges");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "line_types", LRT_EDGE_FLAG_MATERIAL);
+ RNA_def_property_ui_text(
+ prop, "Use Material", "Generate strokes from borders between materials");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edge_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "line_types", LRT_EDGE_FLAG_EDGE_MARK);
+ RNA_def_property_ui_text(prop, "Use Edge Mark", "Generate strokes from freestyle marked edges");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_intersection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "line_types", LRT_EDGE_FLAG_INTERSECTION);
+ RNA_def_property_ui_text(prop, "Use Intersection", "Generate strokes from intersections");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_multiple_levels", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_multiple_levels", 0);
+ RNA_def_property_ui_text(
+ prop, "Use Occlusion Range", "Generate strokes from a range of occlusion levels");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "level_start", PROP_INT, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Level Start", "Minimum number of occlusions for the generated strokes");
+ RNA_def_property_range(prop, 0, 128);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "level_end", PROP_INT, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Level End", "Maximum number of occlusions for the generated strokes");
+ RNA_def_property_range(prop, 0, 128);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "target_material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(
+ prop, "Target Material", "Grease Pencil material assigned to the generated strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "target_layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Target Layer", "Grease Pencil layer assigned to the generated strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "source_vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop,
+ "Source Vertex Group",
+ "Match the beginning of vertex group names from mesh objects, match all when left empty");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_LineartGpencilModifier_vgname_set");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selected strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_source_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_SOURCE_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert Vertex Group", "Invert source vertex group values");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "match_output_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_MATCH_OUTPUT_VGROUP);
+ RNA_def_property_ui_text(prop, "Match Output", "Match output vertex group based on name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "soft_selection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_SOFT_SELECTION);
+ RNA_def_property_ui_text(
+ prop, "Clip", "Preserve original vertex weight instead of clipping to 0/1");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "is_baked", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_IS_BAKED);
+ RNA_def_property_ui_text(prop, "Is Baked", "This modifier has baked data");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Thickness", "The thickness for the generated strokes");
+ RNA_def_property_ui_range(prop, 1, 100, 1, 1);
+ RNA_def_property_range(prop, 1, 200);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "Opacity", "The strength value for the generate strokes");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 2);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pre_sample_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Sample Length", "Resolution to sample the generated strokes with");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 2);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_transparency", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_flags", LRT_GPENCIL_TRANSPARENCY_ENABLE);
+ RNA_def_property_ui_text(
+ prop, "Use Transparency", "Use transparency mask from this material in line art");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_match", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_flags", LRT_GPENCIL_TRANSPARENCY_MATCH);
+ RNA_def_property_ui_text(
+ prop, "Match Transparency", "Require matching all transparency masks instead of just one");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_0", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 0);
+ RNA_def_property_ui_text(prop, "Mask 0", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_1", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 1);
+ RNA_def_property_ui_text(prop, "Mask 1", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_2", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 2);
+ RNA_def_property_ui_text(prop, "Mask 2", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_3", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 3);
+ RNA_def_property_ui_text(prop, "Mask 3", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_4", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 4);
+ RNA_def_property_ui_text(prop, "Mask 4", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_5", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 5);
+ RNA_def_property_ui_text(prop, "Mask 5", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_6", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 6);
+ RNA_def_property_ui_text(prop, "Mask 6", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_7", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 7);
+ RNA_def_property_ui_text(prop, "Mask 7", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2379,6 +2665,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencilarmature(brna);
rna_def_modifier_gpencilmultiply(brna);
rna_def_modifier_gpenciltexture(brna);
+ rna_def_modifier_gpencillineart(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index bfcb0039ca8..95972dd444f 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -424,6 +424,7 @@ void RNA_api_window(struct StructRNA *srna);
void RNA_api_wm(struct StructRNA *srna);
void RNA_api_space_node(struct StructRNA *srna);
void RNA_api_space_text(struct StructRNA *srna);
+void RNA_api_space_filebrowser(struct StructRNA *srna);
void RNA_api_region_view3d(struct StructRNA *srna);
void RNA_api_texture(struct StructRNA *srna);
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index e6ed0f69300..0c0260c889c 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -453,11 +453,10 @@ typedef struct EnumPropertyRNA {
PropEnumGetFunc get;
PropEnumSetFunc set;
- PropEnumItemFunc itemf;
+ PropEnumItemFunc item_fn;
PropEnumGetFuncEx get_ex;
PropEnumSetFuncEx set_ex;
- void *py_data; /* store py callback here */
const EnumPropertyItem *item;
int totitem;
@@ -471,7 +470,7 @@ typedef struct PointerPropertyRNA {
PropPointerGetFunc get;
PropPointerSetFunc set;
- PropPointerTypeFunc typef;
+ PropPointerTypeFunc type_fn;
/** unlike operators, 'set' can still run if poll fails, used for filtering display. */
PropPointerPollFunc poll;
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 84c831a178e..99673f31eb9 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -127,6 +127,14 @@ static void rna_MaterialGpencil_update(Main *bmain, Scene *scene, PointerRNA *pt
WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
}
+static void rna_MaterialLineArt_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Material *ma = (Material *)ptr->owner_id;
+ /* Need to tag geometry for line art modifier updates. */
+ DEG_id_tag_update(&ma->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma);
+}
+
static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Material *ma = (Material *)ptr->owner_id;
@@ -671,6 +679,70 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
}
+static void rna_def_material_lineart(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MaterialLineArt", NULL);
+ RNA_def_struct_sdna(srna, "MaterialLineArt");
+ RNA_def_struct_ui_text(srna, "Material Line Art", "");
+
+ prop = RNA_def_property(srna, "use_transparency", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_MATERIAL_TRANSPARENCY_ENABLED);
+ RNA_def_property_ui_text(
+ prop, "Use Transparency", "Use transparency mask from this material in line art");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_0", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 0);
+ RNA_def_property_ui_text(prop, "Mask 0", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_1", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 1);
+ RNA_def_property_ui_text(prop, "Mask 1", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_2", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 2);
+ RNA_def_property_ui_text(prop, "Mask 2", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_3", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 3);
+ RNA_def_property_ui_text(prop, "Mask 3", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_4", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 4);
+ RNA_def_property_ui_text(prop, "Mask 4", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_5", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 5);
+ RNA_def_property_ui_text(prop, "Mask 5", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_6", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 6);
+ RNA_def_property_ui_text(prop, "mask 6", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "transparency_mask_7", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "transparency_mask", 1 << 7);
+ RNA_def_property_ui_text(prop, "Mask 7", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+}
void RNA_def_material(BlenderRNA *brna)
{
@@ -836,7 +908,13 @@ void RNA_def_material(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Is Grease Pencil", "True if this material has grease pencil data");
+ /* line art */
+ prop = RNA_def_property(srna, "lineart", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "lineart");
+ RNA_def_property_ui_text(prop, "Line Art Settings", "Line art settings for material");
+
rna_def_material_greasepencil(brna);
+ rna_def_material_lineart(brna);
RNA_api_material(srna);
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 664dd268c20..98a2b683f18 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1743,8 +1743,7 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_only_control_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_ControlEdges);
- RNA_def_property_ui_text(
- prop, "Optimal Display", "Skip displaying interior subdivided edges");
+ RNA_def_property_ui_text(prop, "Optimal Display", "Skip displaying interior subdivided edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
@@ -2790,6 +2789,11 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_hole_tolerant", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_HoleTolerant);
+ RNA_def_property_ui_text(prop, "Hole Tolerant", "Better results when there are holes (slower)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
/* BMesh debugging options, only used when G_DEBUG is set */
/* BMesh intersection options */
@@ -3135,7 +3139,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 1, FLT_MAX);
RNA_def_property_ui_range(prop, 1, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Horizontal Aspect Ratio", "");
+ RNA_def_property_ui_text(
+ prop, "Aspect X", "Horizontal aspect ratio (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "aspect_y", PROP_FLOAT, PROP_NONE);
@@ -3143,7 +3148,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 1, FLT_MAX);
RNA_def_property_ui_range(prop, 1, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Vertical Aspect Ratio", "");
+ RNA_def_property_ui_text(
+ prop, "Aspect Y", "Vertical aspect ratio (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE);
@@ -3151,7 +3157,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Horizontal Scale", "");
+ RNA_def_property_ui_text(prop, "Scale X", "Horizontal scale (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_NONE);
@@ -3159,7 +3165,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Vertical Scale", "");
+ RNA_def_property_ui_text(prop, "Scale Y", "Vertical scale (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
srna = RNA_def_struct(brna, "UVProjector", NULL);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index dfb882cde33..fc1f692a8bf 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -398,6 +398,19 @@ static const EnumPropertyItem prop_shader_output_target_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
+ {0, "CryptoObject", 0, "Object", "Use Object layer"},
+ {1, "CryptoMaterial", 0, "Material", "Use Material layer"},
+ {2, "CryptoAsset", 0, "Asset", "Use Asset layer"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem rna_node_geometry_mesh_circle_fill_type_items[] = {
+ {GEO_NODE_MESH_CIRCLE_FILL_NONE, "NONE", 0, "None", ""},
+ {GEO_NODE_MESH_CIRCLE_FILL_NGON, "NGON", 0, "N-Gon", ""},
+ {GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN, "TRIANGLE_FAN", 0, "Triangles", ""},
+ {0, NULL, 0, NULL, NULL},
+};
#endif
#define ITEM_ATTRIBUTE \
@@ -1929,6 +1942,23 @@ static void rna_GeometryNodeAttributeRandomize_data_type_update(Main *bmain,
rna_Node_socket_update(bmain, scene, ptr);
}
+static bool attribute_convert_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ CD_PROP_BOOL,
+ CD_PROP_INT32);
+}
+static const EnumPropertyItem *rna_GeometryNodeAttributeConvert_type_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(rna_enum_attribute_type_items, attribute_convert_type_supported);
+}
+
static bool attribute_fill_type_supported(const EnumPropertyItem *item)
{
return ELEM(
@@ -3427,6 +3457,10 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return;
+ }
+
BKE_image_multilayer_index(ima->rr, iuser);
BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_SRC_CHANGE);
@@ -3473,6 +3507,10 @@ static const EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C),
const EnumPropertyItem *item = NULL;
RenderLayer *rl;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return DummyRNA_NULL_items;
+ }
+
if (ima == NULL || ima->rr == NULL) {
*r_free = false;
return DummyRNA_NULL_items;
@@ -3491,8 +3529,12 @@ static bool rna_Node_image_has_layers_get(PointerRNA *ptr)
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return false;
+ }
+
if (!ima || !(ima->rr)) {
- return 0;
+ return false;
}
return RE_layers_have_name(ima->rr);
@@ -3503,8 +3545,12 @@ static bool rna_Node_image_has_views_get(PointerRNA *ptr)
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return false;
+ }
+
if (!ima || !(ima->rr)) {
- return 0;
+ return false;
}
return BLI_listbase_count_at_most(&ima->rr->views, 2) > 1;
@@ -3549,6 +3595,10 @@ static const EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C),
const EnumPropertyItem *item = NULL;
RenderView *rv;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return DummyRNA_NULL_items;
+ }
+
if (ima == NULL || ima->rr == NULL) {
*r_free = false;
return DummyRNA_NULL_items;
@@ -3705,6 +3755,115 @@ static void rna_NodeColorBalance_update_cdl(Main *bmain, Scene *scene, PointerRN
rna_Node_update(bmain, scene, ptr);
}
+static void rna_NodeCryptomatte_source_set(PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ if (node->id && node->custom1 != value) {
+ id_us_min((ID *)node->id);
+ node->id = NULL;
+ }
+ node->custom1 = value;
+}
+
+static int rna_NodeCryptomatte_layer_name_get(PointerRNA *ptr)
+{
+ int index = 0;
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+ LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, index) {
+ if (STREQLEN(storage->layer_name, layer->name, sizeof(storage->layer_name))) {
+ return index;
+ }
+ }
+ return 0;
+}
+
+static void rna_NodeCryptomatte_layer_name_set(PointerRNA *ptr, int new_value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+
+ CryptomatteLayer *layer = BLI_findlink(&storage->runtime.layers, new_value);
+ if (layer) {
+ STRNCPY(storage->layer_name, layer->name);
+ }
+}
+
+static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem template = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ ntreeCompositCryptomatteUpdateLayerNames(node);
+ int layer_index;
+ LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, layer_index) {
+ template.value = layer_index;
+ template.identifier = layer->name;
+ template.name = layer->name;
+ RNA_enum_item_add(&item, &totitem, &template);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static PointerRNA rna_NodeCryptomatte_scene_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ Scene *scene = (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) ? (Scene *)node->id : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene);
+}
+
+static void rna_NodeCryptomatte_scene_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ rna_Node_scene_set(ptr, value, reports);
+ }
+}
+
+static PointerRNA rna_NodeCryptomatte_image_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ Image *image = (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) ? (Image *)node->id : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_Image, image);
+}
+
+static void rna_NodeCryptomatte_image_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ bNode *node = (bNode *)ptr->data;
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ if (node->id)
+ id_us_min((ID *)node->id);
+ if (value.data)
+ id_us_plus((ID *)value.data);
+
+ node->id = value.data;
+ }
+}
+
+static bool rna_NodeCryptomatte_image_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ Image *image = (Image *)value.owner_id;
+ return image->type == IMA_TYPE_MULTILAYER;
+}
+
static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value)
{
bNode *node = (bNode *)ptr->data;
@@ -3733,13 +3892,13 @@ static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value)
static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromAdd((bNodeTree *)ptr->owner_id, ptr->data);
+ ntreeCompositCryptomatteSyncFromAdd(ptr->data);
rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromRemove((bNodeTree *)ptr->owner_id, ptr->data);
+ ntreeCompositCryptomatteSyncFromRemove(ptr->data);
rna_Node_update(bmain, scene, ptr);
}
@@ -8392,12 +8551,11 @@ static void def_cmp_cryptomatte_entry(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
}
-static void def_cmp_cryptomatte(StructRNA *srna)
+static void def_cmp_cryptomatte_common(StructRNA *srna)
{
PropertyRNA *prop;
static float default_1[3] = {1.0f, 1.0f, 1.0f};
- RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
prop = RNA_def_property(srna, "matte_id", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop,
"rna_NodeCryptomatte_matte_get",
@@ -8408,6 +8566,7 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "add", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "runtime.add");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(
@@ -8415,6 +8574,7 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_add");
prop = RNA_def_property(srna, "remove", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "runtime.remove");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(
@@ -8424,6 +8584,73 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove");
}
+static void def_cmp_cryptomatte_legacy(StructRNA *srna)
+{
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ def_cmp_cryptomatte_common(srna);
+}
+
+static void def_cmp_cryptomatte(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem cryptomatte_source_items[] = {
+ {CMP_CRYPTOMATTE_SRC_RENDER, "RENDER", 0, "Render", "Use Cryptomatte passes from a render"},
+ {CMP_CRYPTOMATTE_SRC_IMAGE, "IMAGE", 0, "Image", "Use Cryptomatte passes from an image"},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, cryptomatte_source_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_NodeCryptomatte_source_set", NULL);
+ RNA_def_property_ui_text(prop, "Source", "Where the Cryptomatte passes are loaded from");
+
+ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(
+ prop, "rna_NodeCryptomatte_scene_get", "rna_NodeCryptomatte_scene_set", NULL, NULL);
+ RNA_def_property_struct_type(prop, "Scene");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_ui_text(prop, "Scene", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop,
+ "rna_NodeCryptomatte_image_get",
+ "rna_NodeCryptomatte_image_set",
+ NULL,
+ "rna_NodeCryptomatte_image_poll");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ def_cmp_cryptomatte_common(srna);
+
+ prop = RNA_def_property(srna, "layer_name", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, node_cryptomatte_layer_name_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeCryptomatte_layer_name_get",
+ "rna_NodeCryptomatte_layer_name_set",
+ "rna_NodeCryptomatte_layer_name_itemf");
+ RNA_def_property_ui_text(prop, "Cryptomatte Layer", "What Cryptomatte layer is used");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "entries", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "entries", NULL);
+ RNA_def_property_struct_type(prop, "CryptomatteEntry");
+ RNA_def_property_ui_text(prop, "Mattes", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* Included here instead of defining image_user as a property of the node,
+ * see def_cmp_image for details.
+ * As mentioned in DNA_node_types.h, iuser is the first member of the Cryptomatte
+ * storage type, so we can cast node->storage to ImageUser.
+ * That is required since we can't define the properties from storage->iuser directly... */
+ RNA_def_struct_sdna_from(srna, "ImageUser", "storage");
+ def_node_image_user(srna);
+}
+
static void def_cmp_denoise(StructRNA *srna)
{
PropertyRNA *prop;
@@ -8647,6 +8874,35 @@ static void def_geo_attribute_fill(StructRNA *srna)
"rna_GeometryNodeAttributeFill_domain_itemf");
}
+static void def_geo_attribute_convert(StructRNA *srna)
+{
+ static const EnumPropertyItem rna_enum_attribute_convert_domain_items[] = {
+ {ATTR_DOMAIN_AUTO, "AUTO", 0, "Auto", ""},
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
+ {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"},
+ {ATTR_DOMAIN_CORNER, "CORNER", 0, "Corner", "Attribute on mesh polygon corner"},
+ {ATTR_DOMAIN_POLYGON, "POLYGON", 0, "Polygon", "Attribute on mesh polygons"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeAttributeConvert", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeConvert_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "The data type to save the result attribute with");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_convert_domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_AUTO);
+ RNA_def_property_ui_text(prop, "Domain", "The geometry domain to save the result attribute in");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_attribute_math(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9188,6 +9444,87 @@ static void def_geo_attribute_separate_xyz(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_mesh_circle(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCircle", "storage");
+
+ prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
+ RNA_def_property_ui_text(prop, "Fill Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_geo_mesh_cylinder(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCylinder", "storage");
+
+ prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
+ RNA_def_property_ui_text(prop, "Fill Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_geo_mesh_cone(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCone", "storage");
+
+ prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
+ RNA_def_property_ui_text(prop, "Fill Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_geo_mesh_line(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mode_items[] = {
+ {GEO_NODE_MESH_LINE_MODE_OFFSET,
+ "OFFSET",
+ 0,
+ "Offset",
+ "Specify the offset from one vertex to the next"},
+ {GEO_NODE_MESH_LINE_MODE_END_POINTS,
+ "END_POINTS",
+ 0,
+ "End Points",
+ "Specify the line's start and end points"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem count_mode_items[] = {
+ {GEO_NODE_MESH_LINE_COUNT_TOTAL,
+ "TOTAL",
+ 0,
+ "Count",
+ "Specify the total number of vertices"},
+ {GEO_NODE_MESH_LINE_COUNT_RESOLUTION,
+ "RESOLUTION",
+ 0,
+ "Resolution",
+ "Specify the distance between vertices"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryMeshLine", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "count_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, count_mode_items);
+ RNA_def_property_ui_text(prop, "Count Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
@@ -10042,6 +10379,8 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
brna, "NodeSocketFloatAngle", "NodeSocketInterfaceFloatAngle", PROP_ANGLE);
rna_def_node_socket_float(
brna, "NodeSocketFloatTime", "NodeSocketInterfaceFloatTime", PROP_TIME);
+ rna_def_node_socket_float(
+ brna, "NodeSocketFloatDistance", "NodeSocketInterfaceFloatDistance", PROP_DISTANCE);
rna_def_node_socket_int(brna, "NodeSocketInt", "NodeSocketInterfaceInt", PROP_NONE);
rna_def_node_socket_int(
@@ -10533,6 +10872,11 @@ static void rna_def_node_link(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Valid", "Link is valid");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
+ prop = RNA_def_property(srna, "is_muted", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_LINK_MUTED);
+ RNA_def_struct_ui_text(srna, "Muted", "Link is muted and can be ignored");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
+
prop = RNA_def_property(srna, "from_node", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "fromnode");
RNA_def_property_struct_type(prop, "Node");
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 624aa23fb26..77a4d636adc 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -36,6 +36,7 @@
#include "DNA_shader_fx_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -159,6 +160,21 @@ const EnumPropertyItem rna_enum_object_gpencil_type_items[] = {
{GP_EMPTY, "EMPTY", ICON_EMPTY_AXIS, "Blank", "Create an empty grease pencil object"},
{GP_STROKE, "STROKE", ICON_STROKE, "Stroke", "Create a simple stroke with basic colors"},
{GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object"},
+ {GP_LRT_SCENE,
+ "LRT_SCENE",
+ ICON_SCENE_DATA,
+ "Scene Line Art",
+ "Quickly set up line art for the entire scene"},
+ {GP_LRT_COLLECTION,
+ "LRT_COLLECTION",
+ ICON_OUTLINER_COLLECTION,
+ "Collection Line Art",
+ "Quickly set up line art for the active collection"},
+ {GP_LRT_OBJECT,
+ "LRT_OBJECT",
+ ICON_OBJECT_DATA,
+ "Object Line Art",
+ "Quickly set up line art for the active object"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem parent_type_items[] = {
@@ -2083,6 +2099,12 @@ int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
return (ss && ss->bm);
}
+static void rna_object_lineart_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->owner_id);
+}
+
#else
static void rna_def_vertex_group(BlenderRNA *brna)
@@ -2645,6 +2667,63 @@ static void rna_def_object_display(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
+static void rna_def_object_lineart(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_feature_line_usage_items[] = {
+ {OBJECT_LRT_INHERENT, "INHEREIT", 0, "Inhereit", "Use settings from the parent collection"},
+ {OBJECT_LRT_INCLUDE,
+ "INCLUDE",
+ 0,
+ "Include",
+ "Generate feature lines for this object's data"},
+ {OBJECT_LRT_OCCLUSION_ONLY,
+ "OCCLUSION_ONLY",
+ 0,
+ "Occlusion Only",
+ "Only use the object data to produce occlusion"},
+ {OBJECT_LRT_EXCLUDE,
+ "EXCLUDE",
+ 0,
+ "Exclude",
+ "Don't use this object for Line Art rendering"},
+ {OBJECT_LRT_INTERSECTION_ONLY,
+ "INTERSECTION_ONLY",
+ 0,
+ "Intersection Only",
+ "Only generate intersection lines for this collection"},
+ {OBJECT_LRT_NO_INTERSECTION,
+ "NO_INTERSECTION",
+ 0,
+ "No Intersection",
+ "Include this object but do not generate intersection lines"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "ObjectLineArt", NULL);
+ RNA_def_struct_ui_text(srna, "Object Line Art", "Object line art settings");
+ RNA_def_struct_sdna(srna, "ObjectLineArt");
+
+ prop = RNA_def_property(srna, "usage", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_feature_line_usage_items);
+ RNA_def_property_ui_text(prop, "Usage", "How to use this object in line art calculation");
+ RNA_def_property_update(prop, 0, "rna_object_lineart_update");
+
+ prop = RNA_def_property(srna, "use_crease_override", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", OBJECT_LRT_OWN_CREASE);
+ RNA_def_property_ui_text(
+ prop, "Use Crease", "Use this object's crease setting to overwrite scene global");
+ RNA_def_property_update(prop, 0, "rna_object_lineart_update");
+
+ prop = RNA_def_property(srna, "crease_threshold", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0, DEG2RAD(180.0f));
+ RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(180.0f), 0.01f, 1);
+ RNA_def_property_ui_text(prop, "Crease", "Angles smaller than this will be treated as creases");
+ RNA_def_property_update(prop, 0, "rna_object_lineart_update");
+}
+
static void rna_def_object(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3316,7 +3395,8 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWWIRE);
- RNA_def_property_ui_text(prop, "Display Wire", "Display the object's wireframe over solid shading");
+ RNA_def_property_ui_text(
+ prop, "Display Wire", "Display the object's wireframe over solid shading");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_all_edges", PROP_BOOLEAN, PROP_NONE);
@@ -3413,6 +3493,11 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_Object_display_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Object Display", "Object display settings for 3D viewport");
+ /* Line Art */
+ prop = RNA_def_property(srna, "lineart", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ObjectLineArt");
+ RNA_def_property_ui_text(prop, "Line Art", "Line art settings for the object");
+
RNA_define_lib_overridable(false);
/* anim */
@@ -3433,6 +3518,7 @@ void RNA_def_object(BlenderRNA *brna)
rna_def_face_map(brna);
rna_def_material_slot(brna);
rna_def_object_display(brna);
+ rna_def_object_lineart(brna);
RNA_define_animate_sdna(true);
}
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
index 59704b00391..29516830058 100644
--- a/source/blender/makesrna/intern/rna_pose_api.c
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -38,9 +38,14 @@
#ifdef RNA_RUNTIME
-/* #include "DNA_anim_types.h" */
+# include "BKE_animsys.h"
# include "BKE_armature.h"
-# include "DNA_action_types.h" /* bPose */
+# include "BKE_context.h"
+
+# include "DNA_action_types.h"
+# include "DNA_anim_types.h"
+
+# include "BLI_ghash.h"
static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec)
{
@@ -102,12 +107,49 @@ static void rna_PoseBone_compute_bbone_handles(bPoseChannel *pchan,
BKE_pchan_bbone_handles_compute(
&params, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets);
}
+
+static void rna_Pose_apply_pose_from_action(ID *pose_owner,
+ bContext *C,
+ bAction *action,
+ const float evaluation_time)
+{
+ BLI_assert(GS(pose_owner->name) == ID_OB);
+ Object *pose_owner_ob = (Object *)pose_owner;
+
+ AnimationEvalContext anim_eval_context = {CTX_data_depsgraph_pointer(C), evaluation_time};
+ BKE_pose_apply_action(pose_owner_ob, action, &anim_eval_context);
+
+ /* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */
+ DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner);
+}
+
#else
-void RNA_api_pose(StructRNA *UNUSED(srna))
+void RNA_api_pose(StructRNA *srna)
{
- /* FunctionRNA *func; */
- /* PropertyRNA *parm; */
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "apply_pose_from_action", "rna_Pose_apply_pose_from_action");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(
+ func,
+ "Apply the given action to this pose by evaluating it at a specific time. Only updates the "
+ "pose of selected bones, or all bones if none are selected.");
+
+ parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ parm = RNA_def_float(func,
+ "evaluation_time",
+ 0.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Evaluation Time",
+ "Time at which the given action is evaluated to obtain the pose",
+ -FLT_MAX,
+ FLT_MAX);
}
void RNA_api_pose_channel(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index b0a942cd39e..d8336e79064 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -910,14 +910,14 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C,
return DummyRNA_NULL_items;
}
- if ((eprop->itemf == NULL) || (eprop->itemf == rna_EnumProperty_default_itemf) ||
+ if ((eprop->item_fn == NULL) || (eprop->item_fn == rna_EnumProperty_default_itemf) ||
(ptr->type == &RNA_EnumProperty) || (C == NULL)) {
if (eprop->item) {
return eprop->item;
}
}
- return eprop->itemf(C, ptr, prop, r_free);
+ return eprop->item_fn(C, ptr, prop, r_free);
}
/* XXX - not sure this is needed? */
@@ -1238,6 +1238,8 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop
/* Used for both Pointer and Collection properties. */
static int rna_property_override_diff_propptr(Main *bmain,
+ ID *owner_id_a,
+ ID *owner_id_b,
PointerRNA *propptr_a,
PointerRNA *propptr_b,
eRNACompareMode mode,
@@ -1359,6 +1361,17 @@ static int rna_property_override_diff_propptr(Main *bmain,
* override is not matching its reference anymore. */
opop->flag &= ~IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
}
+ else if ((owner_id_a->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) != 0 ||
+ (owner_id_b->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) != 0) {
+ /* In case one of the owner of the checked property is tagged as needing resync, do
+ * not change the 'match reference' status of its ID pointer properties overrides,
+ * since many non-matching ones are likely due to missing resync. */
+ printf(
+ "%s: Not checking matching ID pointer properties, since owner %s is tagged as "
+ "needing resync.\n",
+ __func__,
+ id_a->name);
+ }
else if (id_a->override_library != NULL && id_a->override_library->reference == id_b) {
opop->flag |= IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
}
@@ -1778,6 +1791,8 @@ int rna_property_override_diff_default(Main *bmain,
PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, rawprop_a);
PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, rawprop_b);
return rna_property_override_diff_propptr(bmain,
+ ptr_a->owner_id,
+ ptr_b->owner_id,
&propptr_a,
&propptr_b,
mode,
@@ -1934,6 +1949,8 @@ int rna_property_override_diff_default(Main *bmain,
else if (is_id || is_valid_for_diffing) {
if (equals || do_create) {
const int eq = rna_property_override_diff_propptr(bmain,
+ ptr_a->owner_id,
+ ptr_b->owner_id,
&iter_a.ptr,
&iter_b.ptr,
mode,
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index b9fc89db0d1..4ff9e3006b4 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3569,7 +3569,6 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
RNA_def_property_ui_text(
@@ -3579,7 +3578,6 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "weight");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
RNA_def_property_ui_text(prop, "Weight", "Weight to assign in vertex groups");
@@ -5977,7 +5975,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "frs_sec");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 1, SHRT_MAX);
- RNA_def_property_ui_range(prop, 1, 120, 1, -1);
+ RNA_def_property_ui_range(prop, 1, 240, 1, -1);
RNA_def_property_ui_text(prop, "FPS", "Framerate, expressed in frames per second");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 409a2f097ed..c0b40bfd526 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -25,6 +25,9 @@
#include "BLT_translation.h"
+#include "BKE_attribute.h"
+#include "BKE_context.h"
+#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_movieclip.h"
@@ -53,7 +56,9 @@
#include "rna_internal.h"
+#include "SEQ_proxy.h"
#include "SEQ_relations.h"
+#include "SEQ_sequencer.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -145,6 +150,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
"Properties",
"Edit properties of active object and related data-blocks"},
{SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"},
+ {SPACE_SPREADSHEET,
+ "SPREADSHEET",
+ ICON_SPREADSHEET,
+ "Spreadsheet",
+ "Explore geometry data in a table"},
{SPACE_USERPREF,
"PREFERENCES",
ICON_PREFERENCES,
@@ -448,6 +458,7 @@ static const EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output Properties"},
{BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer Properties"},
{BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World Properties"},
+ {BCONTEXT_COLLECTION, "COLLECTION", ICON_GROUP, "Collection", "Collection Properties"},
{BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object Properties"},
{BCONTEXT_CONSTRAINT,
"CONSTRAINT",
@@ -571,6 +582,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
return &RNA_SpacePreferences;
case SPACE_CLIP:
return &RNA_SpaceClipEditor;
+ case SPACE_SPREADSHEET:
+ return &RNA_SpaceSpreadsheet;
/* Currently no type info. */
case SPACE_SCRIPT:
@@ -2226,6 +2239,48 @@ static void rna_SequenceEditor_update_cache(Main *UNUSED(bmain),
SEQ_cache_cleanup(scene);
}
+static void seq_build_proxy(bContext *C, PointerRNA *ptr)
+{
+ if (U.sequencer_proxy_setup != USER_SEQ_PROXY_SETUP_AUTOMATIC) {
+ return;
+ }
+
+ SpaceSeq *sseq = ptr->data;
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene, false));
+
+ GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+ wmJob *wm_job = ED_seq_proxy_wm_job_get(C);
+ ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job);
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->type != SEQ_TYPE_MOVIE || seq->strip == NULL || seq->strip->proxy == NULL) {
+ continue;
+ }
+
+ /* Add new proxy size. */
+ seq->strip->proxy->build_size_flags |= SEQ_rendersize_to_proxysize(sseq->render_size);
+
+ /* Build proxy. */
+ SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ }
+
+ BLI_gset_free(file_list, MEM_freeN);
+
+ if (!WM_jobs_is_running(wm_job)) {
+ G.is_break = false;
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
+static void rna_SequenceEditor_render_size_update(bContext *C, PointerRNA *ptr)
+{
+ seq_build_proxy(C, ptr);
+ rna_SequenceEditor_update_cache(CTX_data_main(C), CTX_data_scene(C), ptr);
+}
+
static void rna_Sequencer_view_type_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -2976,6 +3031,72 @@ static void rna_SpaceFileBrowser_browse_mode_update(Main *UNUSED(bmain),
ED_area_tag_refresh(area);
}
+static void rna_SpaceSpreadsheet_pinned_id_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
+ sspreadsheet->pinned_id = value.data;
+}
+
+static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
+ if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ }
+}
+
+const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
+ GeometryComponentType component_type = sspreadsheet->geometry_component_type;
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
+ Object *active_object = CTX_data_active_object(C);
+ Object *used_object = (sspreadsheet->pinned_id && GS(sspreadsheet->pinned_id->name) == ID_OB) ?
+ (Object *)sspreadsheet->pinned_id :
+ active_object;
+ if (used_object != NULL) {
+ if (used_object->type == OB_POINTCLOUD) {
+ component_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
+ }
+ else {
+ component_type = GEO_COMPONENT_TYPE_MESH;
+ }
+ }
+ }
+
+ EnumPropertyItem *item_array = NULL;
+ int items_len = 0;
+ for (const EnumPropertyItem *item = rna_enum_attribute_domain_items; item->identifier != NULL;
+ item++) {
+ if (component_type == GEO_COMPONENT_TYPE_MESH) {
+ if (!ELEM(item->value,
+ ATTR_DOMAIN_CORNER,
+ ATTR_DOMAIN_EDGE,
+ ATTR_DOMAIN_POINT,
+ ATTR_DOMAIN_POLYGON)) {
+ continue;
+ }
+ }
+ if (component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) {
+ if (item->value != ATTR_DOMAIN_POINT) {
+ continue;
+ }
+ }
+ RNA_enum_item_add(&item_array, &items_len, item);
+ }
+ RNA_enum_item_end(&item_array, &items_len);
+
+ *r_free = true;
+ return item_array;
+}
+
#else
static const EnumPropertyItem dt_uv_items[] = {
@@ -5094,12 +5215,11 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
static const EnumPropertyItem proxy_render_size_items[] = {
{SEQ_RENDER_SIZE_NONE, "NONE", 0, "No display", ""},
- {SEQ_RENDER_SIZE_SCENE, "SCENE", 0, "Scene render size", ""},
- {SEQ_RENDER_SIZE_PROXY_25, "PROXY_25", 0, "Proxy size 25%", ""},
- {SEQ_RENDER_SIZE_PROXY_50, "PROXY_50", 0, "Proxy size 50%", ""},
- {SEQ_RENDER_SIZE_PROXY_75, "PROXY_75", 0, "Proxy size 75%", ""},
- {SEQ_RENDER_SIZE_PROXY_100, "PROXY_100", 0, "Proxy size 100%", ""},
- {SEQ_RENDER_SIZE_FULL, "FULL", 0, "No proxy, full render", ""},
+ {SEQ_RENDER_SIZE_SCENE, "SCENE", 0, "Scene size", ""},
+ {SEQ_RENDER_SIZE_PROXY_25, "PROXY_25", 0, "25%", ""},
+ {SEQ_RENDER_SIZE_PROXY_50, "PROXY_50", 0, "50%", ""},
+ {SEQ_RENDER_SIZE_PROXY_75, "PROXY_75", 0, "75%", ""},
+ {SEQ_RENDER_SIZE_PROXY_100, "PROXY_100", 0, "100%", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -5253,7 +5373,15 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop,
"Proxy Render Size",
"Display preview using full resolution or different proxy resolutions");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_render_size_update");
+
+ prop = RNA_def_property(srna, "use_proxies", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXIES);
+ RNA_def_property_ui_text(
+ prop, "Use Proxies", "Use optimized files for faster scrubbing when available");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
/* grease pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
@@ -5674,6 +5802,11 @@ static void rna_def_space_graph(BlenderRNA *brna)
"If any exists, show markers in a separate row at the bottom of the editor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+ prop = RNA_def_property(srna, "show_extrapolation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NO_DRAW_EXTRAPOLATION);
+ RNA_def_property_ui_text(prop, "Show Extrapolation", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL);
@@ -6569,6 +6702,8 @@ static void rna_def_space_filebrowser(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_FILE_PARAMS, "rna_FileBrowser_FSMenu_active_update");
+
+ RNA_api_space_filebrowser(srna);
}
static void rna_def_space_info(BlenderRNA *brna)
@@ -7169,6 +7304,76 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
}
+static void rna_def_space_spreadsheet(BlenderRNA *brna)
+{
+ PropertyRNA *prop;
+ StructRNA *srna;
+
+ static const EnumPropertyItem geometry_component_type_items[] = {
+ {GEO_COMPONENT_TYPE_MESH,
+ "MESH",
+ ICON_MESH_DATA,
+ "Mesh",
+ "Mesh component containing point, corner, edge and polygon data"},
+ {GEO_COMPONENT_TYPE_POINT_CLOUD,
+ "POINTCLOUD",
+ ICON_POINTCLOUD_DATA,
+ "Point Cloud",
+ "Point cloud component containing only point data"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem object_eval_state_items[] = {
+ {SPREADSHEET_OBJECT_EVAL_STATE_FINAL,
+ "FINAL",
+ ICON_NONE,
+ "Final",
+ "Use data from object with all modifiers applied"},
+ {SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL,
+ "ORIGINAL",
+ ICON_NONE,
+ "Original",
+ "Use data from original object without any modifiers applied"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
+ RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
+
+ rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_FOOTER));
+
+ prop = RNA_def_property(srna, "pinned_id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceSpreadsheet_pinned_id_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Pinned ID", "Data-block whose values are displayed");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
+ RNA_def_property_ui_text(
+ prop, "Show Only Selected", "Only include rows that correspond to selected elements");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, geometry_component_type_items);
+ RNA_def_property_ui_text(
+ prop, "Geometry Component", "Part of the geometry to display data from");
+ RNA_def_property_update(prop,
+ NC_SPACE | ND_SPACE_SPREADSHEET,
+ "rna_SpaceSpreadsheet_geometry_component_type_update");
+
+ prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceSpreadsheet_attribute_domain_itemf");
+ RNA_def_property_ui_text(prop, "Attribute Domain", "Attribute domain to display");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "object_eval_state", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, object_eval_state_items);
+ RNA_def_property_ui_text(prop, "Object Evaluation State", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+}
+
void RNA_def_space(BlenderRNA *brna)
{
rna_def_space(brna);
@@ -7194,6 +7399,7 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_node_tree_path(brna);
rna_def_space_node(brna);
rna_def_space_clip(brna);
+ rna_def_space_spreadsheet(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index e4c0ade1533..205a88edf84 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -27,6 +27,7 @@
# include "BKE_global.h"
+# include "ED_fileselect.h"
# include "ED_screen.h"
# include "ED_text.h"
@@ -115,4 +116,24 @@ void RNA_api_space_text(StructRNA *srna)
RNA_def_function_output(func, parm);
}
+void RNA_api_space_filebrowser(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id");
+ RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID");
+
+ parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(parm, "ID");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ parm = RNA_def_boolean(
+ func,
+ "deferred",
+ 0,
+ "",
+ "Whether to activate the ID immediately (false) or after the file browser refreshes (true)");
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index a78bb4cbbd6..edde5a1ed37 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -98,7 +98,7 @@ const EnumPropertyItem rna_enum_preference_section_items[] = {
};
static const EnumPropertyItem audio_device_items[] = {
- {0, "Null", 0, "None", "Null device - there will be no audio output"},
+ {0, "None", 0, "None", "No device - there will be no audio output"},
{0, NULL, 0, NULL, NULL},
};
@@ -3847,6 +3847,26 @@ static void rna_def_userdef_theme_space_statusbar(BlenderRNA *brna)
rna_def_userdef_theme_spaces_main(srna);
}
+static void rna_def_userdef_theme_space_spreadsheet(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* space_spreadsheet */
+
+ srna = RNA_def_struct(brna, "ThemeSpreadsheet", NULL);
+ RNA_def_struct_sdna(srna, "ThemeSpace");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Theme Spreadsheet", "Theme settings for the Spreadsheet");
+
+ prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ rna_def_userdef_theme_spaces_main(srna);
+}
+
static void rna_def_userdef_themes(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3873,14 +3893,14 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
{20, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", ""},
{21, "TOPBAR", ICON_TOPBAR, "Top Bar", ""},
{22, "STATUSBAR", ICON_STATUSBAR, "Status Bar", ""},
+ {23, "SPREADSHEET", ICON_SPREADSHEET, "Spreadsheet"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "Theme", NULL);
RNA_def_struct_sdna(srna, "bTheme");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(
- srna, "Theme", "User interface styling and color settings");
+ RNA_def_struct_ui_text(srna, "Theme", "User interface styling and color settings");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Name of the theme");
@@ -4002,6 +4022,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "space_statusbar");
RNA_def_property_struct_type(prop, "ThemeStatusBar");
RNA_def_property_ui_text(prop, "Status Bar", "");
+
+ prop = RNA_def_property(srna, "spreadsheet", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "space_spreadsheet");
+ RNA_def_property_struct_type(prop, "ThemeSpreadsheet");
+ RNA_def_property_ui_text(prop, "Spreadsheet", "");
/* end space types */
prop = RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE);
@@ -4255,6 +4281,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
rna_def_userdef_theme_space_clip(brna);
rna_def_userdef_theme_space_topbar(brna);
rna_def_userdef_theme_space_statusbar(brna);
+ rna_def_userdef_theme_space_spreadsheet(brna);
rna_def_userdef_theme_colorset(brna);
rna_def_userdef_theme_collection_color(brna);
rna_def_userdef_themes(brna);
@@ -4270,7 +4297,8 @@ static void rna_def_userdef_solidlight(BlenderRNA *brna)
srna = RNA_def_struct(brna, "UserSolidLight", NULL);
RNA_def_struct_sdna(srna, "SolidLight");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Solid Light", "Light used for Studio lighting in solid shading mode");
+ RNA_def_struct_ui_text(
+ srna, "Solid Light", "Light used for Studio lighting in solid shading mode");
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", 1);
@@ -4815,7 +4843,8 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_text_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA);
- RNA_def_property_ui_text(prop, "Text Anti-Aliasing", "Smooth jagged edges of user interface text");
+ RNA_def_property_ui_text(
+ prop, "Text Anti-Aliasing", "Smooth jagged edges of user interface text");
RNA_def_property_update(prop, 0, "rna_userdef_text_update");
prop = RNA_def_property(srna, "text_hinting", PROP_ENUM, PROP_NONE);
@@ -5349,6 +5378,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem seq_proxy_setup_options[] = {
+ {USER_SEQ_PROXY_SETUP_MANUAL, "MANUAL", 0, "Manual", "Set up proxies manually"},
+ {USER_SEQ_PROXY_SETUP_AUTOMATIC,
+ "AUTOMATIC",
+ 0,
+ "Automatic",
+ "Build proxies for added movie and image strips in each preview size"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "PreferencesSystem", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "Preferences");
@@ -5416,6 +5455,13 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Disk Cache Compression Level",
"Smaller compression will result in larger files, but less decoding overhead");
+ /* Sequencer proxy setup */
+
+ prop = RNA_def_property(srna, "sequencer_proxy_setup", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, seq_proxy_setup_options);
+ RNA_def_property_enum_sdna(prop, NULL, "sequencer_proxy_setup");
+ RNA_def_property_ui_text(prop, "Proxy setup", "When and how proxies are created");
+
prop = RNA_def_property(srna, "scrollback", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "scrollback");
RNA_def_property_range(prop, 32, 32768);
@@ -6061,7 +6107,9 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_relative_paths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_RELPATHS);
RNA_def_property_ui_text(
- prop, "Relative Paths", "Default relative path option for the file selector");
+ prop,
+ "Relative Paths",
+ "Default relative path option for the file selector, when no path is defined yet");
prop = RNA_def_property(srna, "use_file_compression", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FILECOMPRESS);
@@ -6186,7 +6234,8 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SAVE_PREVIEWS);
RNA_def_property_ui_text(prop,
"Save Preview Images",
- "Enables automatic saving of preview images in the .blend file");
+ "Enables automatic saving of preview images in the .blend file "
+ "as well as a thumbnail of the .blend");
rna_def_userdef_filepaths_asset_library(brna);
@@ -6213,6 +6262,14 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"Undo Legacy",
"Use legacy undo (slower than the new default one, but may be more stable in some cases)");
+ prop = RNA_def_property(srna, "override_auto_resync", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "no_override_auto_resync", 1);
+ RNA_def_property_ui_text(
+ prop,
+ "Override Auto Resync",
+ "Enable library overrides automatic resync detection and process on file load. Disable when "
+ "dealing with older .blend files that need manual Resync (Enforce) handling");
+
prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index cb20b480ee5..e7ca41bb5be 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -1216,6 +1216,11 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */
RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(
+ func,
+ "Ensure the keymap exists. This will return the one with the given name/space type/region "
+ "type, or create a new one if it does not exist yet.");
+
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 070ba3a1bcf..cc42c89a60e 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -21,7 +21,7 @@
* \ingroup modifiers
*/
-// #ifdef DEBUG_TIME
+// #define DEBUG_TIME
#include <stdio.h>
@@ -422,7 +422,7 @@ static void BMD_mesh_intersection(BMesh *bm,
if (use_exact) {
BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, bmd->operation);
+ bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, false, bmd->operation);
}
else {
BM_mesh_intersect(bm,
@@ -587,8 +587,16 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd,
}
BM_mesh_elem_index_ensure(bm, BM_FACE);
- BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_nary, shape, num_shapes, true, false, bmd->operation);
+ BM_mesh_boolean(bm,
+ looptris,
+ tottri,
+ bm_face_isect_nary,
+ shape,
+ num_shapes,
+ true,
+ false,
+ false,
+ bmd->operation);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
@@ -607,6 +615,23 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd,
}
#ifdef WITH_GMP
+
+/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
+ * If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
+ * or to zero if there aren't enough slots in the destination.
+ * Caller must MEM_freeN the returned array. */
+static short *get_material_remap(Object *dest_ob, Object *src_ob)
+{
+ short *remap;
+ int n = dest_ob->totcol;
+ if (n <= 0) {
+ n = 1;
+ }
+ remap = MEM_mallocN(n * sizeof(short), __func__);
+ BKE_object_material_remap_calc(dest_ob, src_ob, remap);
+ return remap;
+}
+
/* New method: bypass trip through BMesh. */
static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
const ModifierEvalContext *ctx,
@@ -614,25 +639,32 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
{
Mesh *result;
Mesh *mesh_operand;
+ short *remap;
Mesh **meshes = NULL;
const float(**obmats)[4][4] = NULL;
+ short **material_remaps = NULL;
BLI_array_declare(meshes);
BLI_array_declare(obmats);
+ BLI_array_declare(material_remaps);
# ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
# endif
+ if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == NULL) {
+ return mesh;
+ }
+
BLI_array_append(meshes, mesh);
BLI_array_append(obmats, &ctx->object->obmat);
+ BLI_array_append(material_remaps, NULL);
if (bmd->flag & eBooleanModifierFlag_Object) {
- if (bmd->object == NULL) {
- return mesh;
- }
mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
BLI_array_append(meshes, mesh_operand);
BLI_array_append(obmats, &bmd->object->obmat);
+ remap = get_material_remap(ctx->object, bmd->object);
+ BLI_array_append(material_remaps, remap);
}
else if (bmd->flag & eBooleanModifierFlag_Collection) {
Collection *collection = bmd->collection;
@@ -644,6 +676,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
BLI_array_append(meshes, collection_mesh);
BLI_array_append(obmats, &ob->obmat);
+ remap = get_material_remap(ctx->object, ob);
+ BLI_array_append(material_remaps, remap);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@@ -651,14 +685,24 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
}
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
+ const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
result = BKE_mesh_boolean((const Mesh **)meshes,
(const float(**)[4][4])obmats,
+ (const short **)material_remaps,
BLI_array_len(meshes),
use_self,
+ hole_tolerant,
bmd->operation);
BLI_array_free(meshes);
BLI_array_free(obmats);
+ for (int i = 0; i < BLI_array_len(material_remaps); i++) {
+ remap = material_remaps[i];
+ if (remap) {
+ MEM_freeN(remap);
+ }
+ }
+ BLI_array_free(material_remaps);
# ifdef DEBUG_TIME
TIMEIT_END(boolean_bmesh);
@@ -846,31 +890,44 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "collection", 0, NULL, ICON_NONE);
}
+ uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ modifier_panel_end(layout, ptr);
+}
+
+static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
+
const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact;
+ const bool operand_object = RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object;
- uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiLayoutSetPropSep(layout, true);
+ uiLayout *col = uiLayoutColumn(layout, true);
if (use_exact) {
/* When operand is collection, we always use_self. */
if (operand_object) {
- uiItemR(layout, ptr, "use_self", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_self", 0, NULL, ICON_NONE);
}
+ uiItemR(col, ptr, "use_hole_tolerant", 0, NULL, ICON_NONE);
}
else {
- uiItemR(layout, ptr, "double_threshold", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "double_threshold", 0, NULL, ICON_NONE);
}
if (G.debug) {
- uiLayout *col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "debug_options", 0, NULL, ICON_NONE);
}
-
- modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
- modifier_panel_register(region_type, eModifierType_Boolean, panel_draw);
+ PanelType *panel = modifier_panel_register(region_type, eModifierType_Boolean, panel_draw);
+ modifier_subpanel_register(
+ region_type, "solver_options", "Solver Options", NULL, solver_options_panel_draw, panel);
}
ModifierTypeInfo modifierType_Boolean = {
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index b47f5806c9c..003002e5fac 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -77,6 +77,7 @@
#include "NOD_type_callbacks.hh"
using blender::float3;
+using blender::FunctionRef;
using blender::IndexRange;
using blender::Map;
using blender::Set;
@@ -90,8 +91,8 @@ using blender::bke::PersistentObjectHandle;
using blender::fn::GMutablePointer;
using blender::fn::GValueMap;
using blender::nodes::GeoNodeExecParams;
-using namespace blender::nodes::derived_node_tree_types;
using namespace blender::fn::multi_function_types;
+using namespace blender::nodes::derived_node_tree_types;
static void initData(ModifierData *md)
{
@@ -254,8 +255,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
class GeometryNodesEvaluator {
private:
blender::LinearAllocator<> allocator_;
- Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_;
- Vector<const DInputSocket *> group_outputs_;
+ Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_;
+ Vector<DInputSocket> group_outputs_;
blender::nodes::MultiFunctionByNode &mf_by_node_;
const blender::nodes::DataTypeConversions &conversions_;
const PersistentDataHandleMap &handle_map_;
@@ -264,8 +265,8 @@ class GeometryNodesEvaluator {
Depsgraph *depsgraph_;
public:
- GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
- Vector<const DInputSocket *> group_outputs,
+ GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data,
+ Vector<DInputSocket> group_outputs,
blender::nodes::MultiFunctionByNode &mf_by_node,
const PersistentDataHandleMap &handle_map,
const Object *self_object,
@@ -280,15 +281,15 @@ class GeometryNodesEvaluator {
depsgraph_(depsgraph)
{
for (auto item : group_input_data.items()) {
- this->forward_to_inputs(*item.key, item.value);
+ this->forward_to_inputs(item.key, item.value);
}
}
Vector<GMutablePointer> execute()
{
Vector<GMutablePointer> results;
- for (const DInputSocket *group_output : group_outputs_) {
- Vector<GMutablePointer> result = this->get_input_values(*group_output);
+ for (const DInputSocket &group_output : group_outputs_) {
+ Vector<GMutablePointer> result = this->get_input_values(group_output);
results.append(result[0]);
}
for (GMutablePointer value : value_by_input_.values()) {
@@ -298,62 +299,81 @@ class GeometryNodesEvaluator {
}
private:
- Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute)
+ Vector<GMutablePointer> get_input_values(const DInputSocket socket_to_compute)
{
+ Vector<DSocket> from_sockets;
+ socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); });
- Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
- Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
- const int total_inputs = from_sockets.size() + from_group_inputs.size();
-
- if (total_inputs == 0) {
+ if (from_sockets.is_empty()) {
/* The input is not connected, use the value from the socket itself. */
- return {get_unlinked_input_value(socket_to_compute)};
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
+ return {get_unlinked_input_value(socket_to_compute, type)};
}
- if (from_group_inputs.size() == 1) {
- return {get_unlinked_input_value(socket_to_compute)};
+ /* Multi-input sockets contain a vector of inputs. */
+ if (socket_to_compute->is_multi_input_socket()) {
+ return this->get_inputs_from_incoming_links(socket_to_compute, from_sockets);
}
- /* Multi-input sockets contain a vector of inputs. */
- if (socket_to_compute.is_multi_input_socket()) {
- Vector<GMutablePointer> values;
- for (const DOutputSocket *from_socket : from_sockets) {
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- &socket_to_compute, from_socket);
- std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
- if (value.has_value()) {
- values.append(*value);
- }
- else {
- this->compute_output_and_forward(*from_socket);
- GMutablePointer value = value_by_input_.pop(key);
- values.append(value);
- }
+ const DSocket from_socket = from_sockets[0];
+ GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket);
+ return {value};
+ }
+
+ Vector<GMutablePointer> get_inputs_from_incoming_links(const DInputSocket socket_to_compute,
+ const Span<DSocket> from_sockets)
+ {
+ Vector<GMutablePointer> values;
+ for (const int i : from_sockets.index_range()) {
+ const DSocket from_socket = from_sockets[i];
+ const int first_occurence = from_sockets.take_front(i).first_index_try(from_socket);
+ if (first_occurence == -1) {
+ values.append(this->get_input_from_incoming_link(socket_to_compute, from_socket));
+ }
+ else {
+ /* If the same from-socket occurs more than once, we make a copy of the first value. This
+ * can happen when a node linked to a multi-input-socket is muted. */
+ GMutablePointer value = values[first_occurence];
+ const CPPType *type = value.type();
+ void *copy_buffer = allocator_.allocate(type->size(), type->alignment());
+ type->copy_to_uninitialized(value.get(), copy_buffer);
+ values.append({type, copy_buffer});
}
- return values;
}
+ return values;
+ }
+
+ GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute,
+ const DSocket from_socket)
+ {
+ if (from_socket->is_output()) {
+ const DOutputSocket from_output_socket{from_socket};
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(socket_to_compute,
+ from_output_socket);
+ std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
+ if (value.has_value()) {
+ /* This input has been computed before, return it directly. */
+ return {*value};
+ }
- const DOutputSocket &from_socket = *from_sockets[0];
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- &socket_to_compute, &from_socket);
- std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
- if (value.has_value()) {
- /* This input has been computed before, return it directly. */
- return {*value};
+ /* Compute the socket now. */
+ this->compute_output_and_forward(from_output_socket);
+ return {value_by_input_.pop(key)};
}
- /* Compute the socket now. */
- this->compute_output_and_forward(from_socket);
- return {value_by_input_.pop(key)};
+ /* Get value from an unlinked input socket. */
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
+ const DInputSocket from_input_socket{from_socket};
+ return {get_unlinked_input_value(from_input_socket, type)};
}
- void compute_output_and_forward(const DOutputSocket &socket_to_compute)
+ void compute_output_and_forward(const DOutputSocket socket_to_compute)
{
- const DNode &node = socket_to_compute.node();
+ const DNode node{socket_to_compute.context(), &socket_to_compute->node()};
- if (!socket_to_compute.is_available()) {
+ if (!socket_to_compute->is_available()) {
/* If the output is not available, use a default value. */
- const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo());
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(type.default_value(), buffer);
this->forward_to_inputs(socket_to_compute, {type, buffer});
@@ -362,9 +382,9 @@ class GeometryNodesEvaluator {
/* Prepare inputs required to execute the node. */
GValueMap<StringRef> node_inputs_map{allocator_};
- for (const DInputSocket *input_socket : node.inputs()) {
+ for (const InputSocketRef *input_socket : node->inputs()) {
if (input_socket->is_available()) {
- Vector<GMutablePointer> values = this->get_input_values(*input_socket);
+ Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket});
for (int i = 0; i < values.size(); ++i) {
/* Values from Multi Input Sockets are stored in input map with the format
* <identifier>[<index>]. */
@@ -382,15 +402,15 @@ class GeometryNodesEvaluator {
this->execute_node(node, params);
/* Forward computed outputs to linked input sockets. */
- for (const DOutputSocket *output_socket : node.outputs()) {
+ for (const OutputSocketRef *output_socket : node->outputs()) {
if (output_socket->is_available()) {
GMutablePointer value = node_outputs_map.extract(output_socket->identifier());
- this->forward_to_inputs(*output_socket, value);
+ this->forward_to_inputs({node.context(), output_socket}, value);
}
}
}
- void execute_node(const DNode &node, GeoNodeExecParams params)
+ void execute_node(const DNode node, GeoNodeExecParams params)
{
const bNode &bnode = params.node();
@@ -403,7 +423,7 @@ class GeometryNodesEvaluator {
}
/* Use the multi-function implementation if it exists. */
- const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr);
+ const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr);
if (multi_function != nullptr) {
this->execute_multi_function_node(node, params, *multi_function);
return;
@@ -413,51 +433,60 @@ class GeometryNodesEvaluator {
this->execute_unknown_node(node, params);
}
- void store_ui_hints(const DNode &node, GeoNodeExecParams params) const
+ void store_ui_hints(const DNode node, GeoNodeExecParams params) const
{
- for (const DInputSocket *dsocket : node.inputs()) {
- if (!dsocket->is_available()) {
+ for (const InputSocketRef *socket_ref : node->inputs()) {
+ if (!socket_ref->is_available()) {
continue;
}
- if (dsocket->bsocket()->type != SOCK_GEOMETRY) {
+ if (socket_ref->bsocket()->type != SOCK_GEOMETRY) {
+ continue;
+ }
+ if (socket_ref->is_multi_input_socket()) {
+ /* Not needed currently. */
continue;
}
- bNodeTree *btree_cow = node.node_ref().tree().btree();
+ bNodeTree *btree_cow = node->btree();
bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
- const GeometrySet &geometry_set = params.get_input<GeometrySet>(dsocket->identifier());
+ const GeometrySet &geometry_set = params.get_input<GeometrySet>(socket_ref->identifier());
const Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
for (const GeometryComponent *component : components) {
- component->attribute_foreach([&](StringRefNull attribute_name,
- const AttributeMetaData &UNUSED(meta_data)) {
- BKE_nodetree_attribute_hint_add(*btree_original, context, *node.bnode(), attribute_name);
- return true;
- });
+ component->attribute_foreach(
+ [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
+ BKE_nodetree_attribute_hint_add(*btree_original,
+ context,
+ *node->bnode(),
+ attribute_name,
+ meta_data.domain,
+ meta_data.data_type);
+ return true;
+ });
}
}
}
- void execute_multi_function_node(const DNode &node,
+ void execute_multi_function_node(const DNode node,
GeoNodeExecParams params,
const MultiFunction &fn)
{
MFContextBuilder fn_context;
MFParamsBuilder fn_params{fn, 1};
Vector<GMutablePointer> input_data;
- for (const DInputSocket *dsocket : node.inputs()) {
- if (dsocket->is_available()) {
- GMutablePointer data = params.extract_input(dsocket->identifier());
+ for (const InputSocketRef *socket_ref : node->inputs()) {
+ if (socket_ref->is_available()) {
+ GMutablePointer data = params.extract_input(socket_ref->identifier());
fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1));
input_data.append(data);
}
}
Vector<GMutablePointer> output_data;
- for (const DOutputSocket *dsocket : node.outputs()) {
- if (dsocket->is_available()) {
- const CPPType &type = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo());
+ for (const OutputSocketRef *socket_ref : node->outputs()) {
+ if (socket_ref->is_available()) {
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
output_data.append(GMutablePointer(type, buffer));
@@ -468,19 +497,19 @@ class GeometryNodesEvaluator {
value.destruct();
}
int output_index = 0;
- for (const int i : node.outputs().index_range()) {
- if (node.output(i).is_available()) {
+ for (const int i : node->outputs().index_range()) {
+ if (node->output(i).is_available()) {
GMutablePointer value = output_data[output_index];
- params.set_output_by_move(node.output(i).identifier(), value);
+ params.set_output_by_move(node->output(i).identifier(), value);
value.destruct();
output_index++;
}
}
}
- void execute_unknown_node(const DNode &node, GeoNodeExecParams params)
+ void execute_unknown_node(const DNode node, GeoNodeExecParams params)
{
- for (const DOutputSocket *socket : node.outputs()) {
+ for (const OutputSocketRef *socket : node->outputs()) {
if (socket->is_available()) {
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
params.set_output_by_copy(socket->identifier(), {type, type.default_value()});
@@ -488,17 +517,18 @@ class GeometryNodesEvaluator {
}
}
- void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
+ void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward)
{
/* For all sockets that are linked with the from_socket push the value to their node. */
- Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
+ Vector<DInputSocket> to_sockets_all;
+ from_socket.foreach_target_socket(
+ [&](DInputSocket to_socket) { to_sockets_all.append_non_duplicates(to_socket); });
const CPPType &from_type = *value_to_forward.type();
- Vector<const DInputSocket *> to_sockets_same_type;
- for (const DInputSocket *to_socket : to_sockets_all) {
+ Vector<DInputSocket> to_sockets_same_type;
+ for (const DInputSocket &to_socket : to_sockets_all) {
const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- to_socket, &from_socket);
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
if (from_type == to_type) {
to_sockets_same_type.append(to_socket);
}
@@ -520,23 +550,21 @@ class GeometryNodesEvaluator {
}
else if (to_sockets_same_type.size() == 1) {
/* This value is only used on one input socket, no need to copy it. */
- const DInputSocket *to_socket = to_sockets_same_type[0];
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- to_socket, &from_socket);
+ const DInputSocket to_socket = to_sockets_same_type[0];
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
add_value_to_input_socket(key, value_to_forward);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
- const DInputSocket *first_to_socket = to_sockets_same_type[0];
- Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
+ const DInputSocket first_to_socket = to_sockets_same_type[0];
+ Span<DInputSocket> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
const CPPType &type = *value_to_forward.type();
- const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair(
- first_to_socket, &from_socket);
+ const std::pair<DInputSocket, DOutputSocket> first_key = std::make_pair(first_to_socket,
+ from_socket);
add_value_to_input_socket(first_key, value_to_forward);
- for (const DInputSocket *to_socket : other_to_sockets) {
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- to_socket, &from_socket);
+ for (const DInputSocket &to_socket : other_to_sockets) {
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(value_to_forward.get(), buffer);
add_value_to_input_socket(key, GMutablePointer{type, buffer});
@@ -544,22 +572,17 @@ class GeometryNodesEvaluator {
}
}
- void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key,
+ void add_value_to_input_socket(const std::pair<DInputSocket, DOutputSocket> key,
GMutablePointer value)
{
value_by_input_.add_new(key, value);
}
- GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
+ GMutablePointer get_unlinked_input_value(const DInputSocket &socket,
+ const CPPType &required_type)
{
- bNodeSocket *bsocket;
- if (socket.linked_group_inputs().size() == 0) {
- bsocket = socket.bsocket();
- }
- else {
- bsocket = socket.linked_group_inputs()[0]->bsocket();
- }
- const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo());
+ bNodeSocket *bsocket = socket->bsocket();
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
if (bsocket->type == SOCK_OBJECT) {
@@ -576,7 +599,19 @@ class GeometryNodesEvaluator {
blender::nodes::socket_cpp_value_get(*bsocket, buffer);
}
- return {type, buffer};
+ if (type == required_type) {
+ return {type, buffer};
+ }
+ if (conversions_.is_convertible(type, required_type)) {
+ void *converted_buffer = allocator_.allocate(required_type.size(),
+ required_type.alignment());
+ conversions_.convert(type, required_type, buffer, converted_buffer);
+ type.destruct(buffer);
+ return {required_type, converted_buffer};
+ }
+ void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment());
+ type.copy_to_uninitialized(type.default_value(), default_buffer);
+ return {required_type, default_buffer};
}
};
@@ -616,7 +651,7 @@ static IDProperty *socket_add_property(IDProperty *settings_prop_group,
prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY;
- /* Make the group in the ui container group to hold the property's UI settings. */
+ /* Make the group in the UI container group to hold the property's UI settings. */
IDProperty *prop_ui_group;
{
IDPropertyTemplate idprop = {0};
@@ -985,7 +1020,7 @@ static void fill_data_handle_map(const NodesModifierSettings &settings,
{
Set<ID *> used_ids;
find_used_ids_from_settings(settings, used_ids);
- find_used_ids_from_nodes(*tree.btree(), used_ids);
+ find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids);
int current_handle = 0;
for (ID *id : used_ids) {
@@ -1013,8 +1048,8 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
* often than necessary. It's going to be replaced soon.
*/
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
- Span<const DOutputSocket *> group_input_sockets,
- const DInputSocket &socket_to_compute,
+ Span<const OutputSocketRef *> group_input_sockets,
+ const InputSocketRef &socket_to_compute,
GeometrySet input_geometry_set,
NodesModifierData *nmd,
const ModifierEvalContext *ctx)
@@ -1026,32 +1061,33 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
PersistentDataHandleMap handle_map;
fill_data_handle_map(nmd->settings, tree, handle_map);
- Map<const DOutputSocket *, GMutablePointer> group_inputs;
+ Map<DOutputSocket, GMutablePointer> group_inputs;
+ const DTreeContext *root_context = &tree.root_context();
if (group_input_sockets.size() > 0) {
- Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets;
+ Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets;
/* If the group expects a geometry as first input, use the geometry that has been passed to
* modifier. */
- const DOutputSocket *first_input_socket = group_input_sockets[0];
+ const OutputSocketRef *first_input_socket = group_input_sockets[0];
if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
- GeometrySet *geometry_set_in = allocator.construct<GeometrySet>(
- std::move(input_geometry_set));
- group_inputs.add_new(first_input_socket, geometry_set_in);
+ GeometrySet *geometry_set_in =
+ allocator.construct<GeometrySet>(std::move(input_geometry_set)).release();
+ group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
remaining_input_sockets = remaining_input_sockets.drop_front(1);
}
/* Initialize remaining group inputs. */
- for (const DOutputSocket *socket : remaining_input_sockets) {
+ for (const OutputSocketRef *socket : remaining_input_sockets) {
const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in);
- group_inputs.add_new(socket, {cpp_type, value_in});
+ group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
}
}
- Vector<const DInputSocket *> group_outputs;
- group_outputs.append(&socket_to_compute);
+ Vector<DInputSocket> group_outputs;
+ group_outputs.append({root_context, &socket_to_compute});
GeometryNodesEvaluator evaluator{group_inputs,
group_outputs,
@@ -1126,16 +1162,17 @@ static void modifyGeometry(ModifierData *md,
check_property_socket_sync(ctx->object, md);
- blender::nodes::NodeTreeRefMap tree_refs;
- DerivedNodeTree tree{nmd->node_group, tree_refs};
+ NodeTreeRefMap tree_refs;
+ DerivedNodeTree tree{*nmd->node_group, tree_refs};
if (tree.has_link_cycles()) {
BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
return;
}
- Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput");
- Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput");
+ const NodeTreeRef &root_tree_ref = tree.root_context().tree();
+ Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
+ Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
if (input_nodes.size() > 1) {
return;
@@ -1144,16 +1181,18 @@ static void modifyGeometry(ModifierData *md,
return;
}
- Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ?
- input_nodes[0]->outputs().drop_back(1) :
- Span<const DOutputSocket *>{};
- Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1);
+ Span<const OutputSocketRef *> group_inputs;
+ if (input_nodes.size() == 1) {
+ group_inputs = input_nodes[0]->outputs().drop_back(1);
+ }
+
+ Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1);
if (group_outputs.size() == 0) {
return;
}
- const DInputSocket *group_output = group_outputs[0];
+ const InputSocketRef *group_output = group_outputs[0];
if (group_output->idname() != "NodeSocketGeometry") {
return;
}
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 821c74496f2..6b2facc16a2 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -409,13 +409,9 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
*/
PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
{
- /* Get the name for the modifier's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- BKE_modifier_type_panel_id(type, panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BKE_modifier_type_panel_id(type, panel_type->idname);
BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -450,13 +446,9 @@ PanelType *modifier_subpanel_register(ARegionType *region_type,
PanelDrawFn draw,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 8122f4617c1..3162a33edc2 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -135,10 +135,11 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
return mesh;
}
- /* make sure there are UV Maps available */
-
+ /* Create a new layer if no UV Maps are available
+ * (e.g. if a preceding modifier could not preserve it). */
if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
- return mesh;
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, mesh->totloop, umd->uvlayer_name);
}
/* make sure we're using an existing layer */
@@ -330,12 +331,25 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
+ /* Aspect and Scale are only used for camera projectors. */
+ bool has_camera = false;
+ RNA_BEGIN (ptr, projector_ptr, "projectors") {
+ PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object");
+ if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) {
+ has_camera = true;
+ break;
+ }
+ }
+ RNA_END;
+
sub = uiLayoutColumn(layout, true);
- uiItemR(sub, ptr, "aspect_x", 0, IFACE_("Aspect X"), ICON_NONE);
+ uiLayoutSetActive(sub, has_camera);
+ uiItemR(sub, ptr, "aspect_x", 0, NULL, ICON_NONE);
uiItemR(sub, ptr, "aspect_y", 0, IFACE_("Y"), ICON_NONE);
sub = uiLayoutColumn(layout, true);
- uiItemR(sub, ptr, "scale_x", 0, IFACE_("Scale X"), ICON_NONE);
+ uiLayoutSetActive(sub, has_camera);
+ uiItemR(sub, ptr, "scale_x", 0, NULL, ICON_NONE);
uiItemR(sub, ptr, "scale_y", 0, IFACE_("Y"), ICON_NONE);
uiItemR(layout, ptr, "projector_count", 0, IFACE_("Projectors"), ICON_NONE);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 8c5081555fc..366cac48a40 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -62,7 +62,7 @@ set(SRC
composite/nodes/node_composite_composite.c
composite/nodes/node_composite_cornerpin.c
composite/nodes/node_composite_crop.c
- composite/nodes/node_composite_cryptomatte.c
+ composite/nodes/node_composite_cryptomatte.cc
composite/nodes/node_composite_curves.c
composite/nodes/node_composite_defocus.c
composite/nodes/node_composite_denoise.c
@@ -146,6 +146,7 @@ set(SRC
geometry/nodes/node_geo_attribute_color_ramp.cc
geometry/nodes/node_geo_attribute_combine_xyz.cc
geometry/nodes/node_geo_attribute_compare.cc
+ geometry/nodes/node_geo_attribute_convert.cc
geometry/nodes/node_geo_attribute_fill.cc
geometry/nodes/node_geo_attribute_math.cc
geometry/nodes/node_geo_attribute_mix.cc
@@ -154,12 +155,21 @@ set(SRC
geometry/nodes/node_geo_attribute_sample_texture.cc
geometry/nodes/node_geo_attribute_separate_xyz.cc
geometry/nodes/node_geo_attribute_vector_math.cc
+ geometry/nodes/node_geo_attribute_remove.cc
geometry/nodes/node_geo_boolean.cc
geometry/nodes/node_geo_collection_info.cc
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_is_viewport.cc
geometry/nodes/node_geo_join_geometry.cc
+ geometry/nodes/node_geo_mesh_primitive_circle.cc
+ geometry/nodes/node_geo_mesh_primitive_cone.cc
+ geometry/nodes/node_geo_mesh_primitive_cube.cc
+ geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+ geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+ geometry/nodes/node_geo_mesh_primitive_line.cc
+ geometry/nodes/node_geo_mesh_primitive_plane.cc
+ geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_point_distribute.cc
geometry/nodes/node_geo_point_instance.cc
@@ -168,8 +178,8 @@ set(SRC
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_point_translate.cc
geometry/nodes/node_geo_points_to_volume.cc
+ geometry/nodes/node_geo_subdivide.cc
geometry/nodes/node_geo_subdivision_surface.cc
- geometry/nodes/node_geo_subdivision_surface_simple.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
geometry/nodes/node_geo_volume_to_mesh.cc
@@ -259,7 +269,7 @@ set(SRC
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
shader/nodes/node_shader_vector_math.cc
- shader/nodes/node_shader_vector_rotate.c
+ shader/nodes/node_shader_vector_rotate.cc
shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_volume_absorption.c
shader/nodes/node_shader_volume_info.c
@@ -302,7 +312,6 @@ set(SRC
intern/node_exec.c
intern/node_geometry_exec.cc
intern/node_socket.cc
- intern/node_tree_dependencies.cc
intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/node_util.c
@@ -321,7 +330,6 @@ set(SRC
NOD_geometry.h
NOD_geometry_exec.hh
NOD_math_functions.hh
- NOD_node_tree_dependencies.hh
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
NOD_shader.h
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 6ad02986010..b0dd0edeec5 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -106,6 +106,7 @@ void register_node_type_cmp_doubleedgemask(void);
void register_node_type_cmp_keyingscreen(void);
void register_node_type_cmp_keying(void);
void register_node_type_cmp_cryptomatte(void);
+void register_node_type_cmp_cryptomatte_legacy(void);
void register_node_type_cmp_translate(void);
void register_node_type_cmp_rotate(void);
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index 62affe43895..3529336baf6 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -19,546 +19,361 @@
/** \file
* \ingroup nodes
*
- * DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It
- * builds on top of NodeTreeRef and supports similar queries efficiently.
- *
- * Every inlined node remembers its path to the parent ("call stack").
- *
- * Unlinked group node inputs are handled separately from other sockets.
- *
- * There is a dot graph exporter for debugging purposes.
+ * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more
+ * convenient and safe. It does so by pairing nodes and sockets with a context. The context
+ * contains information about the current "instance" of the node or socket. A node might be
+ * "instanced" multiple times when it is in a node group that is used multiple times.
*/
-#include "NOD_node_tree_ref.hh"
-
+#include "BLI_function_ref.hh"
#include "BLI_vector_set.hh"
+#include "NOD_node_tree_ref.hh"
+
namespace blender::nodes {
+class DTreeContext;
+class DerivedNodeTree;
+
+class DNode;
class DSocket;
class DInputSocket;
class DOutputSocket;
-class DNode;
-class DParentNode;
-class DGroupInput;
-class DerivedNodeTree;
-class DSocket : NonCopyable, NonMovable {
- protected:
- DNode *node_;
- const SocketRef *socket_ref_;
- int id_;
+/**
+ * The context attached to every node or socket in a derived node tree. It can be used to determine
+ * the place of a node in a hierarchy of node groups.
+ *
+ * Contexts are organized in a tree data structure to avoid having to store the entire path to the
+ * root node group for every node/socket.
+ */
+class DTreeContext {
+ private:
+ /* Null when this context is for the root node group. Otherwise it points to the context one
+ * level up. */
+ DTreeContext *parent_context_;
+ /* Null when this context is for the root node group. Otherwise it points to the group node in
+ * the parent node group that contains this context. */
+ const NodeRef *parent_node_;
+ /* The current node tree. */
+ const NodeTreeRef *tree_;
+ /* All the children contexts of this context. */
+ Map<const NodeRef *, DTreeContext *> children_;
friend DerivedNodeTree;
public:
- const DNode &node() const;
-
- int id() const;
- int index() const;
-
- bool is_input() const;
- bool is_output() const;
-
- const DSocket &as_base() const;
- const DInputSocket &as_input() const;
- const DOutputSocket &as_output() const;
-
- PointerRNA *rna() const;
- StringRefNull idname() const;
- StringRefNull name() const;
- StringRefNull identifier() const;
- bNodeSocketType *typeinfo() const;
-
- const SocketRef &socket_ref() const;
- bNodeSocket *bsocket() const;
-
- bool is_available() const;
+ const NodeTreeRef &tree() const;
+ const DTreeContext *parent_context() const;
+ const NodeRef *parent_node() const;
+ const DTreeContext *child_context(const NodeRef &node) const;
+ bool is_root() const;
};
-class DInputSocket : public DSocket {
+/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested
+ * node group hierarchy. This type is small and can be passed around by value. */
+class DNode {
private:
- Vector<DOutputSocket *> linked_sockets_;
- Vector<DGroupInput *> linked_group_inputs_;
- bool is_multi_input_socket_;
-
- friend DerivedNodeTree;
+ const DTreeContext *context_ = nullptr;
+ const NodeRef *node_ref_ = nullptr;
public:
- const InputSocketRef &socket_ref() const;
-
- Span<const DOutputSocket *> linked_sockets() const;
- Span<const DGroupInput *> linked_group_inputs() const;
-
- bool is_linked() const;
- bool is_multi_input_socket() const;
-};
+ DNode() = default;
+ DNode(const DTreeContext *context, const NodeRef *node);
-class DOutputSocket : public DSocket {
- private:
- Vector<DInputSocket *> linked_sockets_;
+ const DTreeContext *context() const;
+ const NodeRef *node_ref() const;
+ const NodeRef *operator->() const;
- friend DerivedNodeTree;
+ friend bool operator==(const DNode &a, const DNode &b);
+ friend bool operator!=(const DNode &a, const DNode &b);
+ operator bool() const;
- public:
- const OutputSocketRef &socket_ref() const;
- Span<const DInputSocket *> linked_sockets() const;
+ uint64_t hash() const;
};
-class DGroupInput : NonCopyable, NonMovable {
- private:
- const InputSocketRef *socket_ref_;
- DParentNode *parent_;
- Vector<DInputSocket *> linked_sockets_;
- int id_;
-
- friend DerivedNodeTree;
+/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
+ * nested node group hierarchy. This type is small and can be passed around by value.
+ *
+ * A #DSocket can represent an input or an output socket. If the type of a socket is known at
+ * compile time is is preferable to use #DInputSocket or #DOutputSocket instead. */
+class DSocket {
+ protected:
+ const DTreeContext *context_ = nullptr;
+ const SocketRef *socket_ref_ = nullptr;
public:
- const InputSocketRef &socket_ref() const;
- bNodeSocket *bsocket() const;
- const DParentNode *parent() const;
- Span<const DInputSocket *> linked_sockets() const;
- int id() const;
- StringRefNull name() const;
-};
-
-class DNode : NonCopyable, NonMovable {
- private:
- const NodeRef *node_ref_;
- DParentNode *parent_;
+ DSocket() = default;
+ DSocket(const DTreeContext *context, const SocketRef *socket);
+ DSocket(const DInputSocket &input_socket);
+ DSocket(const DOutputSocket &output_socket);
- Span<DInputSocket *> inputs_;
- Span<DOutputSocket *> outputs_;
+ const DTreeContext *context() const;
+ const SocketRef *socket_ref() const;
+ const SocketRef *operator->() const;
- int id_;
+ friend bool operator==(const DSocket &a, const DSocket &b);
+ friend bool operator!=(const DSocket &a, const DSocket &b);
+ operator bool() const;
- friend DerivedNodeTree;
+ uint64_t hash() const;
+};
+/* A (nullable) reference to an input socket and the context it is in. */
+class DInputSocket : public DSocket {
public:
- const NodeRef &node_ref() const;
- const DParentNode *parent() const;
-
- Span<const DInputSocket *> inputs() const;
- Span<const DOutputSocket *> outputs() const;
-
- const DInputSocket &input(int index) const;
- const DOutputSocket &output(int index) const;
-
- const DInputSocket &input(int index, StringRef expected_name) const;
- const DOutputSocket &output(int index, StringRef expected_name) const;
+ DInputSocket() = default;
+ DInputSocket(const DTreeContext *context, const InputSocketRef *socket);
+ explicit DInputSocket(const DSocket &base_socket);
- int id() const;
+ const InputSocketRef *socket_ref() const;
+ const InputSocketRef *operator->() const;
- PointerRNA *rna() const;
- StringRefNull idname() const;
- StringRefNull name() const;
- bNode *bnode() const;
- bNodeType *typeinfo() const;
+ DOutputSocket get_corresponding_group_node_output() const;
+ Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
- private:
- void destruct_with_sockets();
+ void foreach_origin_socket(FunctionRef<void(DSocket)> callback,
+ const bool follow_only_first_incoming_link = false) const;
};
-class DParentNode : NonCopyable, NonMovable {
- private:
- const NodeRef *node_ref_;
- DParentNode *parent_;
- int id_;
+/* A (nullable) reference to an output socket and the context it is in. */
+class DOutputSocket : public DSocket {
+ public:
+ DOutputSocket() = default;
+ DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket);
+ explicit DOutputSocket(const DSocket &base_socket);
- friend DerivedNodeTree;
+ const OutputSocketRef *socket_ref() const;
+ const OutputSocketRef *operator->() const;
- public:
- const DParentNode *parent() const;
- const NodeRef &node_ref() const;
- int id() const;
-};
+ DInputSocket get_corresponding_group_node_input() const;
+ DInputSocket get_active_corresponding_group_output_socket() const;
-using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>;
+ void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const;
+};
-class DerivedNodeTree : NonCopyable, NonMovable {
+class DerivedNodeTree {
private:
LinearAllocator<> allocator_;
- Vector<DNode *> nodes_by_id_;
- Vector<DGroupInput *> group_inputs_;
- Vector<DParentNode *> parent_nodes_;
-
- Vector<DSocket *> sockets_by_id_;
- Vector<DInputSocket *> input_sockets_;
- Vector<DOutputSocket *> output_sockets_;
-
- MultiValueMap<const bNodeType *, DNode *> nodes_by_type_;
+ DTreeContext *root_context_;
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
- bNodeTree *btree_;
public:
- DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs);
+ DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
~DerivedNodeTree();
- bNodeTree *btree() const;
-
- Span<const DNode *> nodes() const;
- Span<const DNode *> nodes_by_type(StringRefNull idname) const;
- Span<const DNode *> nodes_by_type(const bNodeType *nodetype) const;
-
- Span<const DSocket *> sockets() const;
- Span<const DInputSocket *> input_sockets() const;
- Span<const DOutputSocket *> output_sockets() const;
-
- Span<const DGroupInput *> group_inputs() const;
-
+ const DTreeContext &root_context() const;
Span<const NodeTreeRef *> used_node_tree_refs() const;
bool has_link_cycles() const;
-
- std::string to_dot() const;
+ void foreach_node(FunctionRef<void(DNode)> callback) const;
private:
- /* Utility functions used during construction. */
- void insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref,
- DParentNode *parent,
- Vector<DNode *> &all_nodes);
- DNode &create_node(const NodeRef &node_ref,
- DParentNode *parent,
- MutableSpan<DSocket *> r_sockets_map);
- void expand_groups(Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs);
- void expand_group_node(DNode &group_node,
- Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs);
- void create_group_inputs_for_unlinked_inputs(DNode &node,
- Vector<DGroupInput *> &all_group_inputs);
- void relink_group_inputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node);
- void relink_group_outputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node);
- void remove_expanded_group_interfaces(Vector<DNode *> &all_nodes);
- void remove_unused_group_inputs(Vector<DGroupInput *> &all_group_inputs);
- void relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes);
- void relink_muted_node(DNode &muted_node);
- void store_in_this_and_init_ids(Vector<DNode *> &&all_nodes,
- Vector<DGroupInput *> &&all_group_inputs,
- Vector<DParentNode *> &&all_parent_nodes);
+ DTreeContext &construct_context_recursively(DTreeContext *parent_context,
+ const NodeRef *parent_node,
+ bNodeTree &btree,
+ NodeTreeRefMap &node_tree_refs);
+ void destruct_context_recursively(DTreeContext *context);
+
+ void foreach_node_in_context_recursive(const DTreeContext &context,
+ FunctionRef<void(DNode)> callback) const;
};
namespace derived_node_tree_types {
+using namespace node_tree_ref_types;
using nodes::DerivedNodeTree;
-using nodes::DGroupInput;
using nodes::DInputSocket;
using nodes::DNode;
using nodes::DOutputSocket;
-using nodes::DParentNode;
-}; // namespace derived_node_tree_types
+using nodes::DSocket;
+using nodes::DTreeContext;
+} // namespace derived_node_tree_types
/* --------------------------------------------------------------------
- * DSocket inline methods.
+ * DTreeContext inline methods.
*/
-inline const DNode &DSocket::node() const
-{
- return *node_;
-}
-
-inline int DSocket::id() const
+inline const NodeTreeRef &DTreeContext::tree() const
{
- return id_;
+ return *tree_;
}
-inline int DSocket::index() const
+inline const DTreeContext *DTreeContext::parent_context() const
{
- return socket_ref_->index();
+ return parent_context_;
}
-inline bool DSocket::is_input() const
+inline const NodeRef *DTreeContext::parent_node() const
{
- return socket_ref_->is_input();
+ return parent_node_;
}
-inline bool DSocket::is_output() const
+inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const
{
- return socket_ref_->is_output();
+ return children_.lookup_default(&node, nullptr);
}
-inline const DSocket &DSocket::as_base() const
+inline bool DTreeContext::is_root() const
{
- return *this;
+ return parent_context_ == nullptr;
}
-inline const DInputSocket &DSocket::as_input() const
-{
- return static_cast<const DInputSocket &>(*this);
-}
-
-inline const DOutputSocket &DSocket::as_output() const
-{
- return static_cast<const DOutputSocket &>(*this);
-}
+/* --------------------------------------------------------------------
+ * DNode inline methods.
+ */
-inline PointerRNA *DSocket::rna() const
+inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref)
+ : context_(context), node_ref_(node_ref)
{
- return socket_ref_->rna();
+ BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree());
}
-inline StringRefNull DSocket::idname() const
+inline const DTreeContext *DNode::context() const
{
- return socket_ref_->idname();
+ return context_;
}
-inline StringRefNull DSocket::name() const
+inline const NodeRef *DNode::node_ref() const
{
- return socket_ref_->name();
+ return node_ref_;
}
-inline StringRefNull DSocket::identifier() const
+inline bool operator==(const DNode &a, const DNode &b)
{
- return socket_ref_->identifier();
+ return a.context_ == b.context_ && a.node_ref_ == b.node_ref_;
}
-inline bNodeSocketType *DSocket::typeinfo() const
+inline bool operator!=(const DNode &a, const DNode &b)
{
- return socket_ref_->bsocket()->typeinfo;
+ return !(a == b);
}
-inline const SocketRef &DSocket::socket_ref() const
+inline DNode::operator bool() const
{
- return *socket_ref_;
+ return node_ref_ != nullptr;
}
-inline bNodeSocket *DSocket::bsocket() const
+inline const NodeRef *DNode::operator->() const
{
- return socket_ref_->bsocket();
+ return node_ref_;
}
-inline bool DSocket::is_available() const
+inline uint64_t DNode::hash() const
{
- return (socket_ref_->bsocket()->flag & SOCK_UNAVAIL) == 0;
+ return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_);
}
/* --------------------------------------------------------------------
- * DInputSocket inline methods.
+ * DSocket inline methods.
*/
-inline const InputSocketRef &DInputSocket::socket_ref() const
+inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref)
+ : context_(context), socket_ref_(socket_ref)
{
- return socket_ref_->as_input();
+ BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree());
}
-inline Span<const DOutputSocket *> DInputSocket::linked_sockets() const
+inline DSocket::DSocket(const DInputSocket &input_socket)
+ : DSocket(input_socket.context_, input_socket.socket_ref_)
{
- return linked_sockets_;
}
-inline Span<const DGroupInput *> DInputSocket::linked_group_inputs() const
+inline DSocket::DSocket(const DOutputSocket &output_socket)
+ : DSocket(output_socket.context_, output_socket.socket_ref_)
{
- return linked_group_inputs_;
}
-inline bool DInputSocket::is_linked() const
+inline const DTreeContext *DSocket::context() const
{
- return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0;
+ return context_;
}
-inline bool DInputSocket::is_multi_input_socket() const
+inline const SocketRef *DSocket::socket_ref() const
{
- return is_multi_input_socket_;
+ return socket_ref_;
}
-/* --------------------------------------------------------------------
- * DOutputSocket inline methods.
- */
-
-inline const OutputSocketRef &DOutputSocket::socket_ref() const
+inline bool operator==(const DSocket &a, const DSocket &b)
{
- return socket_ref_->as_output();
+ return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_;
}
-inline Span<const DInputSocket *> DOutputSocket::linked_sockets() const
+inline bool operator!=(const DSocket &a, const DSocket &b)
{
- return linked_sockets_;
+ return !(a == b);
}
-/* --------------------------------------------------------------------
- * DGroupInput inline methods.
- */
-
-inline const InputSocketRef &DGroupInput::socket_ref() const
+inline DSocket::operator bool() const
{
- return *socket_ref_;
+ return socket_ref_ != nullptr;
}
-inline bNodeSocket *DGroupInput::bsocket() const
+inline const SocketRef *DSocket::operator->() const
{
- return socket_ref_->bsocket();
+ return socket_ref_;
}
-inline const DParentNode *DGroupInput::parent() const
+inline uint64_t DSocket::hash() const
{
- return parent_;
-}
-
-inline Span<const DInputSocket *> DGroupInput::linked_sockets() const
-{
- return linked_sockets_;
-}
-
-inline int DGroupInput::id() const
-{
- return id_;
-}
-
-inline StringRefNull DGroupInput::name() const
-{
- return socket_ref_->name();
+ return DefaultHash<const DTreeContext *>{}(context_) ^
+ DefaultHash<const SocketRef *>{}(socket_ref_);
}
/* --------------------------------------------------------------------
- * DNode inline methods.
+ * DInputSocket inline methods.
*/
-inline const NodeRef &DNode::node_ref() const
-{
- return *node_ref_;
-}
-
-inline const DParentNode *DNode::parent() const
-{
- return parent_;
-}
-
-inline Span<const DInputSocket *> DNode::inputs() const
-{
- return inputs_;
-}
-
-inline Span<const DOutputSocket *> DNode::outputs() const
+inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref)
+ : DSocket(context, socket_ref)
{
- return outputs_;
}
-inline const DInputSocket &DNode::input(int index) const
+inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_socket)
{
- return *inputs_[index];
+ BLI_assert(base_socket->is_input());
}
-inline const DOutputSocket &DNode::output(int index) const
+inline const InputSocketRef *DInputSocket::socket_ref() const
{
- return *outputs_[index];
+ return (const InputSocketRef *)socket_ref_;
}
-inline const DInputSocket &DNode::input(int index, StringRef expected_name) const
+inline const InputSocketRef *DInputSocket::operator->() const
{
- const DInputSocket &socket = *inputs_[index];
- BLI_assert(socket.name() == expected_name);
- UNUSED_VARS_NDEBUG(expected_name);
- return socket;
+ return (const InputSocketRef *)socket_ref_;
}
-inline const DOutputSocket &DNode::output(int index, StringRef expected_name) const
-{
- const DOutputSocket &socket = *outputs_[index];
- BLI_assert(socket.name() == expected_name);
- UNUSED_VARS_NDEBUG(expected_name);
- return socket;
-}
-
-inline int DNode::id() const
-{
- return id_;
-}
-
-inline PointerRNA *DNode::rna() const
-{
- return node_ref_->rna();
-}
-
-inline StringRefNull DNode::idname() const
-{
- return node_ref_->idname();
-}
-
-inline StringRefNull DNode::name() const
-{
- return node_ref_->name();
-}
-
-inline bNode *DNode::bnode() const
-{
- return node_ref_->bnode();
-}
+/* --------------------------------------------------------------------
+ * DOutputSocket inline methods.
+ */
-inline bNodeType *DNode::typeinfo() const
+inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref)
+ : DSocket(context, socket_ref)
{
- return node_ref_->bnode()->typeinfo;
}
-/* --------------------------------------------------------------------
- * DParentNode inline methods.
- */
-
-inline const DParentNode *DParentNode::parent() const
+inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_socket)
{
- return parent_;
+ BLI_assert(base_socket->is_output());
}
-inline const NodeRef &DParentNode::node_ref() const
+inline const OutputSocketRef *DOutputSocket::socket_ref() const
{
- return *node_ref_;
+ return (const OutputSocketRef *)socket_ref_;
}
-inline int DParentNode::id() const
+inline const OutputSocketRef *DOutputSocket::operator->() const
{
- return id_;
+ return (const OutputSocketRef *)socket_ref_;
}
/* --------------------------------------------------------------------
* DerivedNodeTree inline methods.
*/
-inline bNodeTree *DerivedNodeTree::btree() const
-{
- return btree_;
-}
-
-inline Span<const DNode *> DerivedNodeTree::nodes() const
-{
- return nodes_by_id_;
-}
-
-inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const
-{
- const bNodeType *nodetype = nodeTypeFind(idname.c_str());
- return this->nodes_by_type(nodetype);
-}
-
-inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const
-{
- return nodes_by_type_.lookup(nodetype);
-}
-
-inline Span<const DSocket *> DerivedNodeTree::sockets() const
-{
- return sockets_by_id_;
-}
-
-inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const
-{
- return input_sockets_;
-}
-
-inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const
-{
- return output_sockets_;
-}
-
-inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const
+inline const DTreeContext &DerivedNodeTree::root_context() const
{
- return group_inputs_;
+ return *root_context_;
}
inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 3ee8067e81a..03115852d80 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -30,6 +30,7 @@ void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_color_ramp(void);
void register_node_type_geo_attribute_combine_xyz(void);
void register_node_type_geo_attribute_compare(void);
+void register_node_type_geo_attribute_convert(void);
void register_node_type_geo_attribute_fill(void);
void register_node_type_geo_attribute_math(void);
void register_node_type_geo_attribute_mix(void);
@@ -37,11 +38,20 @@ void register_node_type_geo_attribute_proximity(void);
void register_node_type_geo_attribute_randomize(void);
void register_node_type_geo_attribute_separate_xyz(void);
void register_node_type_geo_attribute_vector_math(void);
+void register_node_type_geo_attribute_remove(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_collection_info(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);
+void register_node_type_geo_mesh_primitive_circle(void);
+void register_node_type_geo_mesh_primitive_cone(void);
+void register_node_type_geo_mesh_primitive_cube(void);
+void register_node_type_geo_mesh_primitive_plane(void);
+void register_node_type_geo_mesh_primitive_cylinder(void);
+void register_node_type_geo_mesh_primitive_ico_sphere(void);
+void register_node_type_geo_mesh_primitive_line(void);
+void register_node_type_geo_mesh_primitive_uv_sphere(void);
void register_node_type_geo_object_info(void);
void register_node_type_geo_point_distribute(void);
void register_node_type_geo_point_instance(void);
@@ -51,8 +61,8 @@ void register_node_type_geo_point_separate(void);
void register_node_type_geo_point_translate(void);
void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_sample_texture(void);
+void register_node_type_geo_subdivide(void);
void register_node_type_geo_subdivision_surface(void);
-void register_node_type_geo_subdivision_surface_simple(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_volume_to_mesh(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index e648d77337b..5d1a217db9b 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -59,7 +59,7 @@ using fn::GValueMap;
class GeoNodeExecParams {
private:
- const DNode &node_;
+ const DNode node_;
GValueMap<StringRef> &input_values_;
GValueMap<StringRef> &output_values_;
const PersistentDataHandleMap &handle_map_;
@@ -68,7 +68,7 @@ class GeoNodeExecParams {
Depsgraph *depsgraph_;
public:
- GeoNodeExecParams(const DNode &node,
+ GeoNodeExecParams(const DNode node,
GValueMap<StringRef> &input_values,
GValueMap<StringRef> &output_values,
const PersistentDataHandleMap &handle_map,
@@ -120,13 +120,17 @@ class GeoNodeExecParams {
template<typename T> Vector<T> extract_multi_input(StringRef identifier)
{
Vector<T> values;
- values.append(input_values_.extract<T>(identifier));
- int i = 1;
- std::string sub_identifier = identifier + "[1]";
- while (input_values_.contains(sub_identifier)) {
- values.append(input_values_.extract<T>(sub_identifier));
- i++;
- sub_identifier = identifier + "[" + std::to_string(i) + "]";
+ int index = 0;
+ while (true) {
+ std::string sub_identifier = identifier;
+ if (index > 0) {
+ sub_identifier += "[" + std::to_string(index) + "]";
+ }
+ if (!input_values_.contains(sub_identifier)) {
+ break;
+ }
+ values.append(input_values_.extract<T, StringRef>(sub_identifier));
+ index++;
}
return values;
}
@@ -182,7 +186,7 @@ class GeoNodeExecParams {
*/
const bNode &node() const
{
- return *node_.bnode();
+ return *node_->bnode();
}
const PersistentDataHandleMap &handle_map() const
diff --git a/source/blender/nodes/NOD_node_tree_dependencies.hh b/source/blender/nodes/NOD_node_tree_dependencies.hh
deleted file mode 100644
index 13bb2bde2f3..00000000000
--- a/source/blender/nodes/NOD_node_tree_dependencies.hh
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "BLI_vector_set.hh"
-
-#include "DNA_ID.h"
-#include "DNA_object_types.h"
-
-struct bNodeTree;
-
-namespace blender::nodes {
-
-class NodeTreeDependencies {
- private:
- VectorSet<Object *> transform_deps_;
- VectorSet<Object *> geometry_deps_;
- VectorSet<ID *> id_deps_;
-
- public:
- void add_transform_dependency(Object *object)
- {
- if (object == nullptr) {
- return;
- }
- transform_deps_.add(object);
- id_deps_.add(&object->id);
- }
-
- void add_geometry_dependency(Object *object)
- {
- if (object == nullptr) {
- return;
- }
- geometry_deps_.add(object);
- id_deps_.add(&object->id);
- }
-
- bool depends_on(ID *id) const
- {
- return id_deps_.contains(id);
- }
-
- Span<Object *> transform_dependencies()
- {
- return transform_deps_;
- }
-
- Span<Object *> geometry_dependencies()
- {
- return geometry_deps_;
- }
-
- Span<ID *> id_dependencies()
- {
- return id_deps_;
- }
-};
-
-NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree);
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh
index 552ef5509fa..df31ee18369 100644
--- a/source/blender/nodes/NOD_node_tree_multi_function.hh
+++ b/source/blender/nodes/NOD_node_tree_multi_function.hh
@@ -28,14 +28,15 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_type_callbacks.hh"
+#include "BLI_multi_value_map.hh"
#include "BLI_resource_collector.hh"
namespace blender::nodes {
/**
- * A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a
- * fn::MFNetwork. This is necessary for further processing of a multi-function network that has
- * been generated from a node tree.
+ * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This
+ * is necessary for further processing of a multi-function network that has been generated from a
+ * node tree.
*/
class MFNetworkTreeMap {
private:
@@ -47,15 +48,11 @@ class MFNetworkTreeMap {
*/
const DerivedNodeTree &tree_;
fn::MFNetwork &network_;
- Array<Vector<fn::MFSocket *, 1>> sockets_by_dsocket_id_;
- Array<fn::MFOutputSocket *> socket_by_group_input_id_;
+ MultiValueMap<DSocket, fn::MFSocket *> sockets_by_dsocket_;
public:
MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network)
- : tree_(tree),
- network_(network),
- sockets_by_dsocket_id_(tree.sockets().size()),
- socket_by_group_input_id_(tree.group_inputs().size(), nullptr)
+ : tree_(tree), network_(network)
{
}
@@ -76,96 +73,95 @@ class MFNetworkTreeMap {
void add(const DSocket &dsocket, fn::MFSocket &socket)
{
- BLI_assert(dsocket.is_input() == socket.is_input());
- BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0);
- sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ BLI_assert(dsocket->is_input() == socket.is_input());
+ BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty());
+ sockets_by_dsocket_.add(dsocket, &socket);
}
void add(const DInputSocket &dsocket, fn::MFInputSocket &socket)
{
- sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ sockets_by_dsocket_.add(dsocket, &socket);
}
void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket)
{
/* There can be at most one matching output socket. */
- BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0);
- sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty());
+ sockets_by_dsocket_.add(dsocket, &socket);
}
- void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
+ void add(const DTreeContext &context,
+ Span<const InputSocketRef *> dsockets,
+ Span<fn::MFInputSocket *> sockets)
{
assert_same_size(dsockets, sockets);
for (int i : dsockets.index_range()) {
- this->add(*dsockets[i], *sockets[i]);
+ this->add(DInputSocket(&context, dsockets[i]), *sockets[i]);
}
}
- void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
+ void add(const DTreeContext &context,
+ Span<const OutputSocketRef *> dsockets,
+ Span<fn::MFOutputSocket *> sockets)
{
assert_same_size(dsockets, sockets);
for (int i : dsockets.index_range()) {
- this->add(*dsockets[i], *sockets[i]);
+ this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]);
}
}
- void add(const DGroupInput &group_input, fn::MFOutputSocket &socket)
- {
- BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr);
- socket_by_group_input_id_[group_input.id()] = &socket;
- }
-
void add_try_match(const DNode &dnode, fn::MFNode &node)
{
- this->add_try_match(dnode.inputs().cast<const DSocket *>(),
+ this->add_try_match(*dnode.context(),
+ dnode->inputs().cast<const SocketRef *>(),
node.inputs().cast<fn::MFSocket *>());
- this->add_try_match(dnode.outputs().cast<const DSocket *>(),
+ this->add_try_match(*dnode.context(),
+ dnode->outputs().cast<const SocketRef *>(),
node.outputs().cast<fn::MFSocket *>());
}
- void add_try_match(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
+ void add_try_match(const DTreeContext &context,
+ Span<const InputSocketRef *> dsockets,
+ Span<fn::MFInputSocket *> sockets)
{
- this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>());
+ this->add_try_match(
+ context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
}
- void add_try_match(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
+ void add_try_match(const DTreeContext &context,
+ Span<const OutputSocketRef *> dsockets,
+ Span<fn::MFOutputSocket *> sockets)
{
- this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>());
+ this->add_try_match(
+ context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
}
- void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets)
+ void add_try_match(const DTreeContext &context,
+ Span<const SocketRef *> dsockets,
+ Span<fn::MFSocket *> sockets)
{
int used_sockets = 0;
- for (const DSocket *dsocket : dsockets) {
+ for (const SocketRef *dsocket : dsockets) {
if (!dsocket->is_available()) {
continue;
}
- if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
+ if (!socket_is_mf_data_socket(*dsocket->typeinfo())) {
continue;
}
fn::MFSocket *socket = sockets[used_sockets];
- this->add(*dsocket, *socket);
+ this->add(DSocket(&context, dsocket), *socket);
used_sockets++;
}
}
- fn::MFOutputSocket &lookup(const DGroupInput &group_input)
- {
- fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()];
- BLI_assert(socket != nullptr);
- return *socket;
- }
-
fn::MFOutputSocket &lookup(const DOutputSocket &dsocket)
{
- auto &sockets = sockets_by_dsocket_id_[dsocket.id()];
- BLI_assert(sockets.size() == 1);
- return sockets[0]->as_output();
+ return sockets_by_dsocket_.lookup(dsocket)[0]->as_output();
}
Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket)
{
- return sockets_by_dsocket_id_[dsocket.id()].as_span().cast<fn::MFInputSocket *>();
+ return sockets_by_dsocket_.lookup(dsocket).cast<fn::MFInputSocket *>();
}
fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket)
@@ -186,7 +182,7 @@ class MFNetworkTreeMap {
bool is_mapped(const DSocket &dsocket) const
{
- return sockets_by_dsocket_id_[dsocket.id()].size() >= 1;
+ return !sockets_by_dsocket_.lookup(dsocket).is_empty();
}
};
@@ -258,12 +254,7 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
public:
SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket)
- : MFNetworkBuilderBase(common), bsocket_(dsocket.bsocket())
- {
- }
-
- SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input)
- : MFNetworkBuilderBase(common), bsocket_(group_input.bsocket())
+ : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket())
{
}
@@ -331,10 +322,10 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
*/
class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
private:
- const DNode &dnode_;
+ DNode dnode_;
public:
- NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode)
+ NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode)
: MFNetworkBuilderBase(common), dnode_(dnode)
{
}
@@ -352,7 +343,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
const fn::MultiFunction &get_not_implemented_fn()
{
- return this->get_default_fn("Not Implemented (" + dnode_.name() + ")");
+ return this->get_default_fn("Not Implemented (" + dnode_->name() + ")");
}
const fn::MultiFunction &get_default_fn(StringRef name);
@@ -377,7 +368,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
*/
bNode &bnode()
{
- return *dnode_.node_ref().bnode();
+ return *dnode_->bnode();
}
/**
@@ -393,7 +384,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
const DerivedNodeTree &tree,
ResourceCollector &resources);
-using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>;
+using MultiFunctionByNode = Map<DNode, const fn::MultiFunction *>;
MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
ResourceCollector &resources);
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 7fcc117ba93..6b8eb21bf9a 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -25,6 +25,7 @@
* The following queries are supported efficiently:
* - socket -> index of socket
* - socket -> directly linked sockets
+ * - socket -> directly linked links
* - socket -> linked sockets when skipping reroutes
* - socket -> node
* - socket/node -> rna pointer
@@ -44,6 +45,7 @@
*/
#include "BLI_array.hh"
+#include "BLI_function_ref.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_map.hh"
#include "BLI_multi_value_map.hh"
@@ -65,6 +67,8 @@ class InputSocketRef;
class OutputSocketRef;
class NodeRef;
class NodeTreeRef;
+class LinkRef;
+class InternalLinkRef;
class SocketRef : NonCopyable, NonMovable {
protected:
@@ -74,14 +78,17 @@ class SocketRef : NonCopyable, NonMovable {
int id_;
int index_;
PointerRNA rna_;
- Vector<SocketRef *> linked_sockets_;
- Vector<SocketRef *> directly_linked_sockets_;
+ Vector<LinkRef *> directly_linked_links_;
+ /* This is derived data that is cached for easy and fast access. */
+ MutableSpan<SocketRef *> directly_linked_sockets_;
+ MutableSpan<SocketRef *> linked_sockets_without_reroutes_and_muted_links_;
friend NodeTreeRef;
public:
Span<const SocketRef *> linked_sockets() const;
Span<const SocketRef *> directly_linked_sockets() const;
+ Span<const LinkRef *> directly_linked_links() const;
bool is_linked() const;
const NodeRef &node() const;
@@ -102,16 +109,21 @@ class SocketRef : NonCopyable, NonMovable {
StringRefNull idname() const;
StringRefNull name() const;
StringRefNull identifier() const;
+ bNodeSocketType *typeinfo() const;
bNodeSocket *bsocket() const;
bNode *bnode() const;
bNodeTree *btree() const;
+
+ bool is_available() const;
};
class InputSocketRef final : public SocketRef {
public:
Span<const OutputSocketRef *> linked_sockets() const;
Span<const OutputSocketRef *> directly_linked_sockets() const;
+
+ bool is_multi_input_socket() const;
};
class OutputSocketRef final : public SocketRef {
@@ -128,6 +140,7 @@ class NodeRef : NonCopyable, NonMovable {
int id_;
Vector<InputSocketRef *> inputs_;
Vector<OutputSocketRef *> outputs_;
+ Vector<InternalLinkRef *> internal_links_;
friend NodeTreeRef;
@@ -136,6 +149,7 @@ class NodeRef : NonCopyable, NonMovable {
Span<const InputSocketRef *> inputs() const;
Span<const OutputSocketRef *> outputs() const;
+ Span<const InternalLinkRef *> internal_links() const;
const InputSocketRef &input(int index) const;
const OutputSocketRef &output(int index) const;
@@ -146,6 +160,7 @@ class NodeRef : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
+ bNodeType *typeinfo() const;
int id() const;
@@ -156,6 +171,38 @@ class NodeRef : NonCopyable, NonMovable {
bool is_muted() const;
};
+class LinkRef : NonCopyable, NonMovable {
+ private:
+ OutputSocketRef *from_;
+ InputSocketRef *to_;
+ bNodeLink *blink_;
+
+ friend NodeTreeRef;
+
+ public:
+ const OutputSocketRef &from() const;
+ const InputSocketRef &to() const;
+
+ bNodeLink *blink() const;
+
+ bool is_muted() const;
+};
+
+class InternalLinkRef : NonCopyable, NonMovable {
+ private:
+ InputSocketRef *from_;
+ OutputSocketRef *to_;
+ bNodeLink *blink_;
+
+ friend NodeTreeRef;
+
+ public:
+ const InputSocketRef &from() const;
+ const OutputSocketRef &to() const;
+
+ bNodeLink *blink() const;
+};
+
class NodeTreeRef : NonCopyable, NonMovable {
private:
LinearAllocator<> allocator_;
@@ -164,6 +211,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Vector<SocketRef *> sockets_by_id_;
Vector<InputSocketRef *> input_sockets_;
Vector<OutputSocketRef *> output_sockets_;
+ Vector<LinkRef *> links_;
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
public:
@@ -178,6 +226,8 @@ class NodeTreeRef : NonCopyable, NonMovable {
Span<const InputSocketRef *> input_sockets() const;
Span<const OutputSocketRef *> output_sockets() const;
+ Span<const LinkRef *> links() const;
+
bool has_link_cycles() const;
bNodeTree *btree() const;
@@ -192,16 +242,34 @@ class NodeTreeRef : NonCopyable, NonMovable {
OutputSocketRef &find_output_socket(Map<bNode *, NodeRef *> &node_mapping,
bNode *bnode,
bNodeSocket *bsocket);
- void find_targets_skipping_reroutes(OutputSocketRef &socket_ref, Vector<SocketRef *> &r_targets);
+
+ void create_linked_socket_caches();
+ void foreach_origin_skipping_reroutes_and_muted_links(
+ InputSocketRef &socket, FunctionRef<void(OutputSocketRef &)> callback);
+ void foreach_target_skipping_reroutes_and_muted_links(
+ OutputSocketRef &socket, FunctionRef<void(InputSocketRef &)> callback);
};
+using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>;
+
+const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree);
+
+namespace node_tree_ref_types {
+using nodes::InputSocketRef;
+using nodes::NodeRef;
+using nodes::NodeTreeRef;
+using nodes::NodeTreeRefMap;
+using nodes::OutputSocketRef;
+using nodes::SocketRef;
+} // namespace node_tree_ref_types
+
/* --------------------------------------------------------------------
* SocketRef inline methods.
*/
inline Span<const SocketRef *> SocketRef::linked_sockets() const
{
- return linked_sockets_;
+ return linked_sockets_without_reroutes_and_muted_links_;
}
inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const
@@ -209,9 +277,14 @@ inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const
return directly_linked_sockets_;
}
+inline Span<const LinkRef *> SocketRef::directly_linked_links() const
+{
+ return directly_linked_links_;
+}
+
inline bool SocketRef::is_linked() const
{
- return linked_sockets_.size() > 0;
+ return linked_sockets_without_reroutes_and_muted_links_.size() > 0;
}
inline const NodeRef &SocketRef::node() const
@@ -281,6 +354,11 @@ inline StringRefNull SocketRef::identifier() const
return bsocket_->identifier;
}
+inline bNodeSocketType *SocketRef::typeinfo() const
+{
+ return bsocket_->typeinfo;
+}
+
inline bNodeSocket *SocketRef::bsocket() const
{
return bsocket_;
@@ -296,18 +374,29 @@ inline bNodeTree *SocketRef::btree() const
return node_->btree();
}
+inline bool SocketRef::is_available() const
+{
+ return (bsocket_->flag & SOCK_UNAVAIL) == 0;
+}
+
/* --------------------------------------------------------------------
* InputSocketRef inline methods.
*/
inline Span<const OutputSocketRef *> InputSocketRef::linked_sockets() const
{
- return linked_sockets_.as_span().cast<const OutputSocketRef *>();
+ return linked_sockets_without_reroutes_and_muted_links_.as_span()
+ .cast<const OutputSocketRef *>();
}
inline Span<const OutputSocketRef *> InputSocketRef::directly_linked_sockets() const
{
- return directly_linked_sockets_.as_span().cast<const OutputSocketRef *>();
+ return directly_linked_sockets_.cast<const OutputSocketRef *>();
+}
+
+inline bool InputSocketRef::is_multi_input_socket() const
+{
+ return bsocket_->flag & SOCK_MULTI_INPUT;
}
/* --------------------------------------------------------------------
@@ -316,12 +405,12 @@ inline Span<const OutputSocketRef *> InputSocketRef::directly_linked_sockets() c
inline Span<const InputSocketRef *> OutputSocketRef::linked_sockets() const
{
- return linked_sockets_.as_span().cast<const InputSocketRef *>();
+ return linked_sockets_without_reroutes_and_muted_links_.as_span().cast<const InputSocketRef *>();
}
inline Span<const InputSocketRef *> OutputSocketRef::directly_linked_sockets() const
{
- return directly_linked_sockets_.as_span().cast<const InputSocketRef *>();
+ return directly_linked_sockets_.cast<const InputSocketRef *>();
}
/* --------------------------------------------------------------------
@@ -343,6 +432,11 @@ inline Span<const OutputSocketRef *> NodeRef::outputs() const
return outputs_;
}
+inline Span<const InternalLinkRef *> NodeRef::internal_links() const
+{
+ return internal_links_;
+}
+
inline const InputSocketRef &NodeRef::input(int index) const
{
return *inputs_[index];
@@ -378,6 +472,11 @@ inline StringRefNull NodeRef::name() const
return bnode_->name;
}
+inline bNodeType *NodeRef::typeinfo() const
+{
+ return bnode_->typeinfo;
+}
+
inline int NodeRef::id() const
{
return id_;
@@ -409,7 +508,50 @@ inline bool NodeRef::is_muted() const
}
/* --------------------------------------------------------------------
- * NodeRef inline methods.
+ * LinkRef inline methods.
+ */
+
+inline const OutputSocketRef &LinkRef::from() const
+{
+ return *from_;
+}
+
+inline const InputSocketRef &LinkRef::to() const
+{
+ return *to_;
+}
+
+inline bNodeLink *LinkRef::blink() const
+{
+ return blink_;
+}
+
+inline bool LinkRef::is_muted() const
+{
+ return blink_->flag & NODE_LINK_MUTED;
+}
+
+/* --------------------------------------------------------------------
+ * InternalLinkRef inline methods.
+ */
+
+inline const InputSocketRef &InternalLinkRef::from() const
+{
+ return *from_;
+}
+
+inline const OutputSocketRef &InternalLinkRef::to() const
+{
+ return *to_;
+}
+
+inline bNodeLink *InternalLinkRef::blink() const
+{
+ return blink_;
+}
+
+/* --------------------------------------------------------------------
+ * NodeTreeRef inline methods.
*/
inline Span<const NodeRef *> NodeTreeRef::nodes() const
@@ -443,6 +585,11 @@ inline Span<const OutputSocketRef *> NodeTreeRef::output_sockets() const
return output_sockets_;
}
+inline Span<const LinkRef *> NodeTreeRef::links() const
+{
+ return links_;
+}
+
inline bNodeTree *NodeTreeRef::btree() const
{
return btree_;
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 35550bdec48..abb467961b1 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -220,7 +220,8 @@ DefNode(CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELA
DefNode(CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
-DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE_V2", CryptomatteV2, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" )
DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" )
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
@@ -298,7 +299,17 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity,
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE_SIMPLE, 0, "SUBDIVISION_SURFACE_SIMPLE", SubdivisionSurfaceSimple, "Simple Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CONVERT, def_geo_attribute_convert, "ATTRIBUTE_CONVERT", AttributeConvert, "Attribute Convert", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Circle", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, "MESH_PRIMITIVE_CYLINDER", MeshCylinder, "Cylinder", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_PLANE, 0, "MESH_PRIMITIVE_PLANE", MeshPlane, "Plane", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
deleted file mode 100644
index f5308fe2671..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
+++ /dev/null
@@ -1,157 +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.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "BLI_assert.h"
-#include "BLI_dynstr.h"
-#include "BLI_hash_mm3.h"
-#include "BLI_utildefines.h"
-#include "node_composite_util.h"
-
-static CryptomatteEntry *cryptomatte_find(NodeCryptomatte *n, float encoded_hash)
-{
- LISTBASE_FOREACH (CryptomatteEntry *, entry, &n->entries) {
- if (entry->encoded_hash == encoded_hash) {
- return entry;
- }
- }
- return NULL;
-}
-
-static void cryptomatte_add(NodeCryptomatte *n, float f)
-{
- /* Check if entry already exist. */
- if (cryptomatte_find(n, f) != NULL) {
- return;
- }
- CryptomatteEntry *entry = MEM_callocN(sizeof(CryptomatteEntry), __func__);
- entry->encoded_hash = f;
- BLI_addtail(&n->entries, entry);
-}
-
-static void cryptomatte_remove(NodeCryptomatte *n, float f)
-{
- CryptomatteEntry *entry = cryptomatte_find(n, f);
- if (entry == NULL) {
- return;
- }
-
- BLI_remlink(&n->entries, entry);
- MEM_freeN(entry);
-}
-
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {SOCK_RGBA, N_("Pick")},
- {-1, ""},
-};
-
-void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeCryptomatte *n = node->storage;
- if (n->add[0] != 0.0f) {
- cryptomatte_add(n, n->add[0]);
- n->add[0] = 0.0f;
- n->add[1] = 0.0f;
- n->add[2] = 0.0f;
- }
-}
-
-void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeCryptomatte *n = node->storage;
- if (n->remove[0] != 0.0f) {
- cryptomatte_remove(n, n->remove[0]);
- n->remove[0] = 0.0f;
- n->remove[1] = 0.0f;
- n->remove[2] = 0.0f;
- }
-}
-
-bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
-{
- NodeCryptomatte *n = node->storage;
- char sockname[32];
- n->num_inputs++;
- BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
- bNodeSocket *sock = nodeAddStaticSocket(
- ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, sockname);
- return sock;
-}
-
-int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
-{
- NodeCryptomatte *n = node->storage;
- if (n->num_inputs < 2) {
- return 0;
- }
- bNodeSocket *sock = node->inputs.last;
- nodeRemoveSocket(ntree, node, sock);
- n->num_inputs--;
- return 1;
-}
-
-static void init(bNodeTree *ntree, bNode *node)
-{
- NodeCryptomatte *user = MEM_callocN(sizeof(NodeCryptomatte), "cryptomatte user");
- node->storage = user;
-
- nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
-
- /* Add three inputs by default, as recommended by the Cryptomatte specification. */
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
-}
-
-static void node_free_cryptomatte(bNode *node)
-{
- NodeCryptomatte *nc = node->storage;
-
- if (nc) {
- BLI_freelistN(&nc->entries);
- MEM_freeN(nc);
- }
-}
-
-static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
-{
- NodeCryptomatte *src_nc = src_node->storage;
- NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc);
-
- BLI_duplicatelist(&dest_nc->entries, &src_nc->entries);
- dest_node->storage = dest_nc;
-}
-
-void register_node_type_cmp_cryptomatte(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_init(&ntype, init);
- node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
new file mode 100644
index 00000000000..973864be7b3
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+
+#include "BLI_assert.h"
+#include "BLI_dynstr.h"
+#include "BLI_hash_mm3.h"
+#include "BLI_string_ref.hh"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_cryptomatte.hh"
+#include "BKE_global.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+
+#include <optional>
+
+/** \name Cryptomatte
+ * \{ */
+
+static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node(
+ const bNode &node, const int frame_number, const bool use_meta_data)
+{
+ blender::bke::cryptomatte::CryptomatteSessionPtr session;
+ if (node.type != CMP_NODE_CRYPTOMATTE) {
+ return session;
+ }
+
+ NodeCryptomatte *node_cryptomatte = static_cast<NodeCryptomatte *>(node.storage);
+ switch (node.custom1) {
+ case CMP_CRYPTOMATTE_SRC_RENDER: {
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return session;
+ }
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+
+ if (use_meta_data) {
+ Render *render = (scene) ? RE_GetSceneRender(scene) : nullptr;
+ RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ if (render) {
+ RE_ReleaseResult(render);
+ }
+ }
+
+ if (session == nullptr) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_scene(scene));
+ }
+
+ break;
+ }
+
+ case CMP_CRYPTOMATTE_SRC_IMAGE: {
+ Image *image = (Image *)node.id;
+ if (!image) {
+ break;
+ }
+ BLI_assert(GS(image->id.name) == ID_IM);
+
+ ImageUser *iuser = &node_cryptomatte->iuser;
+ BKE_image_user_frame_calc(image, iuser, frame_number);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
+ RenderResult *render_result = image->rr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+ break;
+ }
+ }
+ return session;
+}
+
+extern "C" {
+static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encoded_hash)
+{
+ LISTBASE_FOREACH (CryptomatteEntry *, entry, &n.entries) {
+ if (entry->encoded_hash == encoded_hash) {
+ return entry;
+ }
+ }
+ return nullptr;
+}
+
+static void cryptomatte_add(bNode &node, NodeCryptomatte &node_cryptomatte, float encoded_hash)
+{
+ /* Check if entry already exist. */
+ if (cryptomatte_find(node_cryptomatte, encoded_hash)) {
+ return;
+ }
+
+ CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
+ MEM_callocN(sizeof(CryptomatteEntry), __func__));
+ entry->encoded_hash = encoded_hash;
+ /* TODO(jbakker): Get current frame from scene. */
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ node, 0, true);
+ if (session) {
+ BKE_cryptomatte_find_name(session.get(), encoded_hash, entry->name, sizeof(entry->name));
+ }
+
+ BLI_addtail(&node_cryptomatte.entries, entry);
+}
+
+static void cryptomatte_remove(NodeCryptomatte &n, float encoded_hash)
+{
+ CryptomatteEntry *entry = cryptomatte_find(n, encoded_hash);
+ if (!entry) {
+ return;
+ }
+ BLI_remlink(&n.entries, entry);
+ MEM_freeN(entry);
+}
+
+static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
+ {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
+
+static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
+ {SOCK_RGBA, N_("Image")},
+ {SOCK_FLOAT, N_("Matte")},
+ {SOCK_RGBA, N_("Pick")},
+ {-1, ""},
+};
+
+void ntreeCompositCryptomatteSyncFromAdd(bNode *node)
+{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ if (n->runtime.add[0] != 0.0f) {
+ cryptomatte_add(*node, *n, n->runtime.add[0]);
+ zero_v3(n->runtime.add);
+ }
+}
+
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node)
+{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ if (n->runtime.remove[0] != 0.0f) {
+ cryptomatte_remove(*n, n->runtime.remove[0]);
+ zero_v3(n->runtime.remove);
+ }
+}
+void ntreeCompositCryptomatteUpdateLayerNames(bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ BLI_freelistN(&n->runtime.layers);
+
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ *node, 0, false);
+
+ if (session) {
+ for (blender::StringRef layer_name :
+ blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
+ CryptomatteLayer *layer = static_cast<CryptomatteLayer *>(
+ MEM_callocN(sizeof(CryptomatteLayer), __func__));
+ layer_name.copy(layer->name);
+ BLI_addtail(&n->runtime.layers, layer);
+ }
+ }
+}
+
+void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ NodeCryptomatte *node_cryptomatte = (NodeCryptomatte *)node->storage;
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ *node, 0, false);
+ std::string first_layer_name;
+
+ if (session) {
+ for (blender::StringRef layer_name :
+ blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
+ if (first_layer_name.empty()) {
+ first_layer_name = layer_name;
+ }
+
+ if (layer_name == node_cryptomatte->layer_name) {
+ BLI_strncpy(r_prefix, node_cryptomatte->layer_name, prefix_len);
+ return;
+ }
+ }
+ }
+
+ const char *cstr = first_layer_name.c_str();
+ BLI_strncpy(r_prefix, cstr, prefix_len);
+}
+
+CryptomatteSession *ntreeCompositCryptomatteSession(bNode *node)
+{
+ blender::bke::cryptomatte::CryptomatteSessionPtr session_ptr = cryptomatte_init_from_node(
+ *node, 0, true);
+ return session_ptr.release();
+}
+
+static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCryptomatte *user = static_cast<NodeCryptomatte *>(
+ MEM_callocN(sizeof(NodeCryptomatte), __func__));
+ node->storage = user;
+}
+
+static void node_init_api_cryptomatte(const bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ bNode *node = static_cast<bNode *>(ptr->data);
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ node->id = &scene->id;
+ id_us_plus(node->id);
+}
+
+static void node_free_cryptomatte(bNode *node)
+{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
+ NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage);
+
+ if (nc) {
+ BLI_freelistN(&nc->runtime.layers);
+ BLI_freelistN(&nc->entries);
+ MEM_freeN(nc);
+ }
+}
+
+static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
+{
+ NodeCryptomatte *src_nc = static_cast<NodeCryptomatte *>(src_node->storage);
+ NodeCryptomatte *dest_nc = static_cast<NodeCryptomatte *>(MEM_dupallocN(src_nc));
+
+ BLI_duplicatelist(&dest_nc->entries, &src_nc->entries);
+ BLI_listbase_clear(&dest_nc->runtime.layers);
+ dest_node->storage = dest_nc;
+}
+
+static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ if (STREQ(ntree->idname, "CompositorNodeTree")) {
+ Scene *scene;
+
+ /* See node_composit_poll_rlayers. */
+ for (scene = static_cast<Scene *>(G.main->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
+ if (scene->nodetree == ntree) {
+ break;
+ }
+ }
+
+ return scene != nullptr;
+ }
+ return false;
+}
+
+void register_node_type_cmp_cryptomatte(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out);
+ node_type_init(&ntype, node_init_cryptomatte);
+ ntype.initfunc_api = node_init_api_cryptomatte;
+ ntype.poll = node_poll_cryptomatte;
+ node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ nodeRegisterType(&ntype);
+}
+
+/** \} */
+
+/** \name Cryptomatte Legacy
+ * \{ */
+static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
+{
+ node_init_cryptomatte(ntree, node);
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ char sockname[32];
+ n->num_inputs++;
+ BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
+ bNodeSocket *sock = nodeAddStaticSocket(
+ ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname);
+ return sock;
+}
+
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ if (n->num_inputs < 2) {
+ return 0;
+ }
+ bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last);
+ nodeRemoveSocket(ntree, node, sock);
+ n->num_inputs--;
+ return 1;
+}
+
+void register_node_type_cmp_cryptomatte_legacy(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out);
+ node_type_init(&ntype, node_init_cryptomatte_legacy);
+ node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ nodeRegisterType(&ntype);
+}
+
+/** \} */
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
index 1e22cde721d..3d0ea201239 100644
--- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
+++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
@@ -26,9 +26,10 @@ static void fn_node_group_instance_id_expand_in_mf_network(
{
const blender::nodes::DNode &node = builder.dnode();
std::string id = "/";
- for (const blender::nodes::DParentNode *parent = node.parent(); parent;
- parent = parent->parent()) {
- id = "/" + parent->node_ref().name() + id;
+ for (const blender::nodes::DTreeContext *context = node.context();
+ context->parent_node() != nullptr;
+ context = context->parent_context()) {
+ id = "/" + context->parent_node()->name() + id;
}
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(
std::move(id));
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc
index f3401a2c00d..d0ecb5592da 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc
@@ -67,12 +67,13 @@ static void fn_node_random_float_expand_in_mf_network(
blender::nodes::NodeMFNetworkBuilder &builder)
{
uint32_t function_seed = 1746872341u;
- const blender::nodes::DNode &node = builder.dnode();
+ blender::nodes::DNode node = builder.dnode();
const blender::DefaultHash<blender::StringRefNull> hasher;
- function_seed = 33 * function_seed + hasher(node.name());
- for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr;
- parent = parent->parent()) {
- function_seed = 33 * function_seed + hasher(parent->node_ref().name());
+ function_seed = 33 * function_seed + hasher(node->name());
+ for (const blender::nodes::DTreeContext *context = node.context();
+ context->parent_node() != nullptr;
+ context = context->parent_context()) {
+ function_seed = 33 * function_seed + hasher(context->parent_node()->name());
}
builder.construct_and_set_matching_fn<RandomFloatFunction>(function_seed);
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 87178c52ab9..2c4c7da64cc 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -71,6 +71,17 @@ static void geometry_node_tree_update(bNodeTree *ntree)
ntree_update_reroute_nodes(ntree);
}
+static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCallback func)
+{
+ func(calldata, NODE_CLASS_INPUT, N_("Input"));
+ func(calldata, NODE_CLASS_GEOMETRY, N_("Geometry"));
+ func(calldata, NODE_CLASS_ATTRIBUTE, N_("Attribute"));
+ func(calldata, NODE_CLASS_OP_COLOR, N_("Color"));
+ func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector"));
+ func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor"));
+ func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
+}
+
void register_node_tree_type_geo(void)
{
bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>(
@@ -83,6 +94,7 @@ void register_node_tree_type_geo(void)
tt->rna_ext.srna = &RNA_GeometryNodeTree;
tt->update = geometry_node_tree_update;
tt->get_from_context = geometry_node_tree_get_from_context;
+ tt->foreach_nodeclass = foreach_nodeclass;
ntreeTypeAdd(tt);
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 271e3771006..8eac8bc0a20 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -47,4 +47,17 @@ void update_attribute_input_socket_availabilities(bNode &node,
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
const AttributeDomain domain);
+void transform_mesh(Mesh *mesh,
+ const float3 translation,
+ const float3 rotation,
+ const float3 scale);
+
+Mesh *create_cylinder_or_cone_mesh(const float3 location,
+ const float3 rotation,
+ const float radius_top,
+ const float radius_bottom,
+ const float depth,
+ const int verts_num,
+ const GeometryNodeMeshCircleFillType fill_type);
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
new file mode 100644
index 00000000000..11d220dd903
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
@@ -0,0 +1,164 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static bNodeSocketTemplate geo_node_attribute_convert_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_STRING, N_("Attribute")},
+ {SOCK_STRING, N_("Result")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_attribute_convert_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_attribute_convert_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
+ __func__);
+
+ data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_AUTO;
+ node->storage = data;
+}
+
+namespace blender::nodes {
+
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ StringRef source_name,
+ StringRef result_name)
+{
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+ ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
+ if (source_attribute) {
+ return source_attribute->domain();
+ }
+ return ATTR_DOMAIN_POINT;
+}
+
+static void attribute_convert_calc(GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ const StringRef source_name,
+ const StringRef result_name,
+ const CustomDataType result_type,
+ const AttributeDomain domain)
+{
+ const AttributeDomain result_domain = (domain == ATTR_DOMAIN_AUTO) ?
+ get_result_domain(
+ component, source_name, result_name) :
+ domain;
+
+ ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
+ source_name, result_domain, result_type);
+ if (!source_attribute) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("No attribute with name \"") + source_name + "\"");
+ return;
+ }
+
+ OutputAttributePtr result_attribute = component.attribute_try_get_for_output(
+ result_name, result_domain, result_type);
+ if (!result_attribute) {
+ return;
+ }
+
+ fn::GSpan source_span = source_attribute->get_span();
+ fn::GMutableSpan result_span = result_attribute->get_span_for_write_only();
+ if (source_span.is_empty() || result_span.is_empty()) {
+ return;
+ }
+ BLI_assert(source_span.size() == result_span.size());
+
+ const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(result_type);
+ BLI_assert(cpp_type != nullptr);
+
+ cpp_type->copy_to_initialized_n(source_span.data(), result_span.data(), result_span.size());
+
+ result_attribute.apply_span_and_save();
+}
+
+static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
+ const std::string result_name = params.extract_input<std::string>("Result");
+ const std::string source_name = params.extract_input<std::string>("Attribute");
+ const NodeAttributeConvert &node_storage = *(const NodeAttributeConvert *)params.node().storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type);
+ const AttributeDomain domain = static_cast<AttributeDomain>(node_storage.domain);
+
+ if (result_name.empty()) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ if (geometry_set.has<MeshComponent>()) {
+ attribute_convert_calc(geometry_set.get_component_for_write<MeshComponent>(),
+ params,
+ source_name,
+ result_name,
+ data_type,
+ domain);
+ }
+ if (geometry_set.has<PointCloudComponent>()) {
+ attribute_convert_calc(geometry_set.get_component_for_write<PointCloudComponent>(),
+ params,
+ source_name,
+ result_name,
+ data_type,
+ domain);
+ }
+
+ params.set_output("Geometry", geometry_set);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_attribute_convert()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_attribute_convert_in, geo_node_attribute_convert_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec;
+ ntype.draw_buttons = geo_node_attribute_convert_layout;
+ node_type_init(&ntype, geo_node_attribute_convert_init);
+ node_type_storage(
+ &ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index bb5b5073c32..27c35da7d37 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -224,7 +224,7 @@ static void randomize_attribute_on_component(GeometryComponent &component,
if (operation != GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) {
if (!component.attribute_exists(attribute_name)) {
params.error_message_add(NodeWarningType::Error,
- "No attribute with name '" + attribute_name + "'.");
+ TIP_("No attribute with name \"") + attribute_name + "\"");
return;
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
new file mode 100644
index 00000000000..837f0c3629a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -0,0 +1,87 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_attribute_remove_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_STRING,
+ N_("Attribute"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ -1.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_MULTI_INPUT},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_attribute_remove_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void remove_attribute(GeometryComponent &component,
+ GeoNodeExecParams &params,
+ Span<std::string> attribute_names)
+{
+ for (std::string attribute_name : attribute_names) {
+ if (attribute_name.empty()) {
+ continue;
+ }
+
+ if (!component.attribute_try_delete(attribute_name)) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Cannot delete attribute with name \"") + attribute_name +
+ "\"");
+ }
+ }
+}
+
+static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
+
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
+ if (geometry_set.has<MeshComponent>()) {
+ remove_attribute(
+ geometry_set.get_component_for_write<MeshComponent>(), params, attribute_names);
+ }
+ if (geometry_set.has<PointCloudComponent>()) {
+ remove_attribute(
+ geometry_set.get_component_for_write<PointCloudComponent>(), params, attribute_names);
+ }
+
+ params.set_output("Geometry", geometry_set);
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_attribute_remove()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0);
+ node_type_socket_templates(&ntype, geo_node_attribute_remove_in, geo_node_attribute_remove_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 38215b54640..9f331190420 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -100,7 +100,7 @@ static Mesh *mesh_boolean_calc(const Mesh *mesh_a, const Mesh *mesh_b, int boole
}
BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, boolean_mode);
+ bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, false, boolean_mode);
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh_a);
BM_mesh_free(bm);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 4e15f232934..52512769a47 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -222,8 +222,9 @@ static void join_components(Span<const MeshComponent *> src_components, Geometry
dst_component.replace(new_mesh);
/* Don't copy attributes that are stored directly in the mesh data structs. */
- join_attributes(
- to_base_components(src_components), dst_component, {"position", "material_index"});
+ join_attributes(to_base_components(src_components),
+ dst_component,
+ {"position", "material_index", "normal", "shade_smooth", "crease"});
}
static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
new file mode 100644
index 00000000000..6d286a9d583
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -0,0 +1,244 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_circle_in[] = {
+ {SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
+ {SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_circle_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
+}
+
+static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
+ sizeof(NodeGeometryMeshCircle), __func__);
+
+ node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
+
+ node->storage = node_storage;
+}
+
+namespace blender::nodes {
+
+static int circle_vert_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
+{
+ switch (fill_type) {
+ case GEO_NODE_MESH_CIRCLE_FILL_NONE:
+ case GEO_NODE_MESH_CIRCLE_FILL_NGON:
+ return verts_num;
+ case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
+ return verts_num + 1;
+ }
+ BLI_assert(false);
+ return 0;
+}
+
+static int circle_edge_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
+{
+ switch (fill_type) {
+ case GEO_NODE_MESH_CIRCLE_FILL_NONE:
+ case GEO_NODE_MESH_CIRCLE_FILL_NGON:
+ return verts_num;
+ case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
+ return verts_num * 2;
+ }
+ BLI_assert(false);
+ return 0;
+}
+
+static int circle_corner_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
+{
+ switch (fill_type) {
+ case GEO_NODE_MESH_CIRCLE_FILL_NONE:
+ return 0;
+ case GEO_NODE_MESH_CIRCLE_FILL_NGON:
+ return verts_num;
+ case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
+ return verts_num * 3;
+ }
+ BLI_assert(false);
+ return 0;
+}
+
+static int circle_face_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
+{
+ switch (fill_type) {
+ case GEO_NODE_MESH_CIRCLE_FILL_NONE:
+ return 0;
+ case GEO_NODE_MESH_CIRCLE_FILL_NGON:
+ return 1;
+ case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
+ return verts_num;
+ }
+ BLI_assert(false);
+ return 0;
+}
+
+static Mesh *create_circle_mesh(const float radius,
+ const int verts_num,
+ const GeometryNodeMeshCircleFillType fill_type)
+{
+ Mesh *mesh = BKE_mesh_new_nomain(circle_vert_total(fill_type, verts_num),
+ circle_edge_total(fill_type, verts_num),
+ 0,
+ circle_corner_total(fill_type, verts_num),
+ circle_face_total(fill_type, verts_num));
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ float angle = 0.0f;
+ const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
+ for (MVert &vert : verts) {
+ copy_v3_v3(vert.co, float3(std::cos(angle) * radius, std::sin(angle) * radius, 0.0f));
+ angle += angle_delta;
+ }
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ copy_v3_v3(verts.last().co, float3(0));
+ }
+
+ /* Point all vertex normals in the up direction. */
+ const short up_normal[3] = {0, 0, SHRT_MAX};
+ for (MVert &vert : verts) {
+ copy_v3_v3_short(vert.no, up_normal);
+ }
+
+ /* Create outer edges. */
+ for (const int i : IndexRange(verts_num)) {
+ MEdge &edge = edges[i];
+ edge.v1 = i;
+ edge.v2 = (i + 1) % verts_num;
+ }
+
+ /* Set loose edge flags. */
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) {
+ for (const int i : IndexRange(verts_num)) {
+ MEdge &edge = edges[i];
+ edge.flag |= ME_LOOSEEDGE;
+ }
+ }
+
+ /* Create triangle fan edges. */
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ for (const int i : IndexRange(verts_num)) {
+ MEdge &edge = edges[verts_num + i];
+ edge.v1 = verts_num;
+ edge.v2 = i;
+ }
+ }
+
+ /* Create corners and faces. */
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ MPoly &poly = polys[0];
+ poly.loopstart = 0;
+ poly.totloop = loops.size();
+
+ for (const int i : IndexRange(verts_num)) {
+ MLoop &loop = loops[i];
+ loop.e = i;
+ loop.v = i;
+ }
+ }
+ else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ for (const int i : IndexRange(verts_num)) {
+ MPoly &poly = polys[i];
+ poly.loopstart = 3 * i;
+ poly.totloop = 3;
+
+ MLoop &loop_a = loops[3 * i];
+ loop_a.e = i;
+ loop_a.v = i;
+ MLoop &loop_b = loops[3 * i + 1];
+ loop_b.e = verts_num + ((i + 1) % verts_num);
+ loop_b.v = (i + 1) % verts_num;
+ MLoop &loop_c = loops[3 * i + 2];
+ loop_c.e = verts_num + i;
+ loop_c.v = verts_num;
+ }
+ }
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage;
+
+ const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
+ storage.fill_type;
+
+ const int verts_num = params.extract_input<int>("Vertices");
+ if (verts_num < 3) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const float radius = params.extract_input<float>("Radius");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+
+ Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type);
+
+ BLI_assert(BKE_mesh_is_valid(mesh));
+
+ transform_mesh(mesh, location, rotation, float3(1));
+
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_circle()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Circle", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_circle_in, geo_node_mesh_primitive_circle_out);
+ node_type_init(&ntype, geo_node_mesh_primitive_circle_init);
+ node_type_storage(
+ &ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec;
+ ntype.draw_buttons = geo_node_mesh_primitive_circle_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
new file mode 100644
index 00000000000..5e5dbd91d31
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -0,0 +1,279 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_cone_in[] = {
+ {SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
+ {SOCK_FLOAT, N_("Radius Top"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Radius Bottom"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Depth"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_cone_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
+}
+
+static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
+ sizeof(NodeGeometryMeshCone), __func__);
+
+ node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+
+ node->storage = node_storage;
+}
+
+namespace blender::nodes {
+
+static int vert_total(const GeometryNodeMeshCircleFillType fill_type,
+ const int verts_num,
+ const bool top_is_point,
+ const bool bottom_is_point)
+{
+ int vert_total = 0;
+ if (!top_is_point) {
+ vert_total += verts_num;
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ vert_total++;
+ }
+ }
+ else {
+ vert_total++;
+ }
+ if (!bottom_is_point) {
+ vert_total += verts_num;
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ vert_total++;
+ }
+ }
+ else {
+ vert_total++;
+ }
+
+ return vert_total;
+}
+
+static int edge_total(const GeometryNodeMeshCircleFillType fill_type,
+ const int verts_num,
+ const bool top_is_point,
+ const bool bottom_is_point)
+{
+ if (top_is_point && bottom_is_point) {
+ return 1;
+ }
+
+ int edge_total = 0;
+ if (!top_is_point) {
+ edge_total += verts_num;
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ edge_total += verts_num;
+ }
+ }
+
+ edge_total += verts_num;
+
+ if (!bottom_is_point) {
+ edge_total += verts_num;
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ edge_total += verts_num;
+ }
+ }
+
+ return edge_total;
+}
+
+static int corner_total(const GeometryNodeMeshCircleFillType fill_type,
+ const int verts_num,
+ const bool top_is_point,
+ const bool bottom_is_point)
+{
+ if (top_is_point && bottom_is_point) {
+ return 0;
+ }
+
+ int corner_total = 0;
+ if (!top_is_point) {
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ corner_total += verts_num;
+ }
+ else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ corner_total += verts_num * 3;
+ }
+ }
+
+ if (!top_is_point && !bottom_is_point) {
+ corner_total += verts_num * 4;
+ }
+ else {
+ corner_total += verts_num * 3;
+ }
+
+ if (!bottom_is_point) {
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ corner_total += verts_num;
+ }
+ else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ corner_total += verts_num * 3;
+ }
+ }
+
+ return corner_total;
+}
+
+static int face_total(const GeometryNodeMeshCircleFillType fill_type,
+ const int verts_num,
+ const bool top_is_point,
+ const bool bottom_is_point)
+{
+ if (top_is_point && bottom_is_point) {
+ return 0;
+ }
+
+ int face_total = 0;
+ if (!top_is_point) {
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ face_total++;
+ }
+ else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ face_total += verts_num;
+ }
+ }
+
+ face_total += verts_num;
+
+ if (!bottom_is_point) {
+ if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ face_total++;
+ }
+ else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
+ face_total += verts_num;
+ }
+ }
+
+ return face_total;
+}
+
+Mesh *create_cylinder_or_cone_mesh(const float3 location,
+ const float3 rotation,
+ const float radius_top,
+ const float radius_bottom,
+ const float depth,
+ const int verts_num,
+ const GeometryNodeMeshCircleFillType fill_type)
+{
+ float4x4 transform;
+ loc_eul_size_to_mat4(transform.values, location, rotation, float3(1));
+
+ const bool top_is_point = radius_top == 0.0f;
+ const bool bottom_is_point = radius_bottom == 0.0f;
+
+ const BMeshCreateParams bmcp = {true};
+ const BMAllocTemplate allocsize = {
+ vert_total(fill_type, verts_num, top_is_point, bottom_is_point),
+ edge_total(fill_type, verts_num, top_is_point, bottom_is_point),
+ corner_total(fill_type, verts_num, top_is_point, bottom_is_point),
+ face_total(fill_type, verts_num, top_is_point, bottom_is_point)};
+ BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+
+ const bool cap_end = (fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE);
+ const bool cap_tri = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN);
+ BMO_op_callf(bm,
+ BMO_FLAG_DEFAULTS,
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b "
+ "cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
+ verts_num,
+ radius_bottom,
+ radius_top,
+ cap_end,
+ cap_tri,
+ depth,
+ transform.values,
+ true);
+
+ Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr);
+ BM_mesh_free(bm);
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage;
+
+ const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
+ storage.fill_type;
+
+ const int verts_num = params.extract_input<int>("Vertices");
+ if (verts_num < 3) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const float radius_top = params.extract_input<float>("Radius Top");
+ const float radius_bottom = params.extract_input<float>("Radius Bottom");
+ const float depth = params.extract_input<float>("Depth");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+
+ Mesh *mesh = create_cylinder_or_cone_mesh(
+ location, rotation, radius_top, radius_bottom, depth, verts_num, fill_type);
+
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_cone()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_cone_in, geo_node_mesh_primitive_cone_out);
+ node_type_init(&ntype, geo_node_mesh_primitive_cone_init);
+ node_type_storage(
+ &ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
+ ntype.draw_buttons = geo_node_mesh_primitive_cone_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
new file mode 100644
index 00000000000..5c32ff6b687
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -0,0 +1,84 @@
+/*
+ * 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 "DNA_mesh_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "bmesh.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_cube_in[] = {
+ {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_cube_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static Mesh *create_cube_mesh(const float3 location, const float3 rotation, const float size)
+{
+ float4x4 transform;
+ loc_eul_size_to_mat4(transform.values, location, rotation, float3(size));
+
+ const BMeshCreateParams bmcp = {true};
+ const BMAllocTemplate allocsize = {8, 12, 24, 6};
+ BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+
+ BMO_op_callf(bm,
+ BMO_FLAG_DEFAULTS,
+ "create_cube matrix=%m4 size=%f calc_uvs=%b",
+ transform.values,
+ size,
+ true);
+
+ Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr);
+ BM_mesh_free(bm);
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
+{
+ const float size = params.extract_input<float>("Size");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+
+ Mesh *mesh = create_cube_mesh(location, rotation, size);
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_cube()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_cube_in, geo_node_mesh_primitive_cube_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
new file mode 100644
index 00000000000..158491f40e7
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -0,0 +1,103 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_cylinder_in[] = {
+ {SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
+ {SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Depth"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_cylinder_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
+}
+
+static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
+ sizeof(NodeGeometryMeshCylinder), __func__);
+
+ node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+
+ node->storage = node_storage;
+}
+
+namespace blender::nodes {
+
+static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage;
+
+ const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
+ storage.fill_type;
+
+ const int verts_num = params.extract_input<int>("Vertices");
+ if (verts_num < 3) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const float radius = params.extract_input<float>("Radius");
+ const float depth = params.extract_input<float>("Depth");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+
+ /* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */
+ Mesh *mesh = create_cylinder_or_cone_mesh(
+ location, rotation, radius, radius, depth, verts_num, fill_type);
+
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_cylinder()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_cylinder_in, geo_node_mesh_primitive_cylinder_out);
+ node_type_init(&ntype, geo_node_mesh_primitive_cylinder_init);
+ node_type_storage(
+ &ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec;
+ ntype.draw_buttons = geo_node_mesh_primitive_cylinder_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
new file mode 100644
index 00000000000..9aaccb7d805
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -0,0 +1,91 @@
+/*
+ * 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 "DNA_mesh_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "bmesh.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_ico_sphere_in[] = {
+ {SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_INT, N_("Subdivisions"), 1, 0, 0, 0, 0, 7},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_ico_sphere_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static Mesh *create_ico_sphere_mesh(const float3 location,
+ const float3 rotation,
+ const int subdivisions,
+ const float radius)
+{
+ float4x4 transform;
+ loc_eul_size_to_mat4(transform.values, location, rotation, float3(1.0f));
+
+ const BMeshCreateParams bmcp = {true};
+ const BMAllocTemplate allocsize = {0, 0, 0, 0};
+ BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+
+ BMO_op_callf(bm,
+ BMO_FLAG_DEFAULTS,
+ "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
+ subdivisions,
+ std::abs(radius),
+ transform.values,
+ true);
+
+ Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr);
+ BM_mesh_free(bm);
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
+{
+ const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
+ const float radius = params.extract_input<float>("Radius");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+
+ Mesh *mesh = create_ico_sphere_mesh(location, rotation, subdivisions, radius);
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_ico_sphere()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_ico_sphere_in, geo_node_mesh_primitive_ico_sphere_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
new file mode 100644
index 00000000000..a7d40571c39
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -0,0 +1,188 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_math_matrix.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_line_in[] = {
+ {SOCK_INT, N_("Count"), 10, 0.0f, 0.0f, 0.0f, 1, 10000},
+ {SOCK_FLOAT, N_("Resolution"), 1.0f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR,
+ N_("Start Location"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Offset"), 0.0f, 0.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_line_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ if (RNA_enum_get(ptr, "mode") == GEO_NODE_MESH_LINE_MODE_END_POINTS) {
+ uiItemR(layout, ptr, "count_mode", 0, "", ICON_NONE);
+ }
+}
+
+static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
+ sizeof(NodeGeometryMeshLine), __func__);
+
+ node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL;
+
+ node->storage = node_storage;
+}
+
+static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode *node)
+{
+ bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *resolution_socket = count_socket->next;
+ bNodeSocket *start_socket = resolution_socket->next;
+ bNodeSocket *end_and_offset_socket = start_socket->next;
+
+ const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)node->storage;
+ const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ storage.count_mode;
+
+ node_sock_label(end_and_offset_socket,
+ (mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) ? N_("End Location") :
+ N_("Offset"));
+
+ nodeSetSocketAvailability(resolution_socket,
+ mode == GEO_NODE_MESH_LINE_MODE_END_POINTS &&
+ count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION);
+ nodeSetSocketAvailability(count_socket,
+ mode == GEO_NODE_MESH_LINE_MODE_OFFSET ||
+ count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL);
+}
+
+namespace blender::nodes {
+
+static void fill_edge_data(MutableSpan<MEdge> edges)
+{
+ for (const int i : edges.index_range()) {
+ edges[i].v1 = i;
+ edges[i].v2 = i + 1;
+ edges[i].flag |= ME_LOOSEEDGE;
+ }
+}
+
+static Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
+{
+ if (count < 1) {
+ return nullptr;
+ }
+
+ Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+
+ short normal[3];
+ normal_float_to_short_v3(normal, delta.normalized());
+
+ float3 co = start;
+ for (const int i : verts.index_range()) {
+ copy_v3_v3(verts[i].co, co);
+ copy_v3_v3_short(verts[i].no, normal);
+ co += delta;
+ }
+
+ fill_edge_data(edges);
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage;
+ const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ storage.count_mode;
+
+ Mesh *mesh = nullptr;
+ const float3 start = params.extract_input<float3>("Start Location");
+ if (mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) {
+ /* The label switches to "End Location", but the same socket is used. */
+ const float3 end = params.extract_input<float3>("Offset");
+ const float3 total_delta = end - start;
+
+ if (count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION) {
+ /* Don't allow asymptotic count increase for low resolution values. */
+ const float resolution = std::max(params.extract_input<float>("Resolution"), 0.0001f);
+ const int count = total_delta.length() / resolution + 1;
+ const float3 delta = total_delta.normalized() * resolution;
+ mesh = create_line_mesh(start, delta, count);
+ }
+ else if (count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL) {
+ const int count = params.extract_input<int>("Count");
+ if (count > 1) {
+ const float3 delta = total_delta / (float)(count - 1);
+ mesh = create_line_mesh(start, delta, count);
+ }
+ }
+ }
+ else if (mode == GEO_NODE_MESH_LINE_MODE_OFFSET) {
+ const float3 delta = params.extract_input<float3>("Offset");
+ const int count = params.extract_input<int>("Count");
+ mesh = create_line_mesh(start, delta, count);
+ }
+
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_line()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Line", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_line_in, geo_node_mesh_primitive_line_out);
+ node_type_init(&ntype, geo_node_mesh_primitive_line_init);
+ node_type_update(&ntype, geo_node_mesh_primitive_line_update);
+ node_type_storage(
+ &ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec;
+ ntype.draw_buttons = geo_node_mesh_primitive_line_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc
new file mode 100644
index 00000000000..adb1d4a9eb4
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc
@@ -0,0 +1,183 @@
+/*
+ * 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_map.hh"
+#include "BLI_math_matrix.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_plane_in[] = {
+ {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_INT, N_("Vertices X"), 10, 0.0f, 0.0f, 0.0f, 2, 1000},
+ {SOCK_INT, N_("Vertices Y"), 10, 0.0f, 0.0f, 0.0f, 2, 1000},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_plane_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void calculate_uvs(Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size)
+{
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
+ "uv", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
+ MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+
+ for (const int i : loops.index_range()) {
+ const float3 &co = verts[loops[i].v].co;
+ uvs[i].x = (co.x + size) / (size * 2.0f);
+ uvs[i].y = (co.y + size) / (size * 2.0f);
+ }
+
+ uv_attribute.apply_span_and_save();
+}
+
+static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float size)
+{
+ const int edges_x = verts_x - 1;
+ const int edges_y = verts_y - 1;
+ Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y,
+ edges_x * verts_y + edges_y * verts_x,
+ 0,
+ edges_x * edges_y * 4,
+ edges_x * edges_y);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ {
+ const float dx = size * 2.0f / edges_x;
+ const float dy = size * 2.0f / edges_y;
+ float x = -size;
+ for (const int x_index : IndexRange(verts_x)) {
+ float y = -size;
+ for (const int y_index : IndexRange(verts_y)) {
+ const int vert_index = x_index * verts_y + y_index;
+ verts[vert_index].co[0] = x;
+ verts[vert_index].co[1] = y;
+ verts[vert_index].co[2] = 0.0f;
+ y += dy;
+ }
+ x += dx;
+ }
+ }
+
+ /* Point all vertex normals in the up direction. */
+ const short up_normal[3] = {0, 0, SHRT_MAX};
+ for (MVert &vert : verts) {
+ copy_v3_v3_short(vert.no, up_normal);
+ }
+
+ /* Build the horizontal edges in the X direction. */
+ const int y_edges_start = 0;
+ int edge_index = 0;
+ for (const int x : IndexRange(verts_x)) {
+ for (const int y : IndexRange(edges_y)) {
+ const int vert_index = x * verts_y + y;
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + 1;
+ }
+ }
+
+ /* Build the vertical edges in the Y direction. */
+ const int x_edges_start = edge_index;
+ for (const int y : IndexRange(verts_y)) {
+ for (const int x : IndexRange(edges_x)) {
+ const int vert_index = x * verts_y + y;
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + verts_y;
+ }
+ }
+
+ int loop_index = 0;
+ int poly_index = 0;
+ for (const int x : IndexRange(edges_x)) {
+ for (const int y : IndexRange(edges_y)) {
+ MPoly &poly = polys[poly_index++];
+ poly.loopstart = loop_index;
+ poly.totloop = 4;
+ const int vert_index = x * verts_y + y;
+
+ MLoop &loop_a = loops[loop_index++];
+ loop_a.v = vert_index;
+ loop_a.e = x_edges_start + edges_x * y + x;
+ MLoop &loop_b = loops[loop_index++];
+ loop_b.v = vert_index + verts_y;
+ loop_b.e = y_edges_start + edges_y * (x + 1) + y;
+ MLoop &loop_c = loops[loop_index++];
+ loop_c.v = vert_index + verts_y + 1;
+ loop_c.e = x_edges_start + edges_x * (y + 1) + x;
+ MLoop &loop_d = loops[loop_index++];
+ loop_d.v = vert_index + 1;
+ loop_d.e = y_edges_start + edges_y * x + y;
+ }
+ }
+
+ calculate_uvs(mesh, verts, loops, size);
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params)
+{
+ const float size = params.extract_input<float>("Size");
+ const int verts_x = params.extract_input<int>("Vertices X");
+ const int verts_y = params.extract_input<int>("Vertices Y");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+ if (verts_x < 2 || verts_y < 2) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ Mesh *mesh = create_plane_mesh(verts_x, verts_y, size);
+ BLI_assert(BKE_mesh_is_valid(mesh));
+
+ transform_mesh(mesh, location, rotation, float3(1));
+
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_plane()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_PLANE, "Plane", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_plane_in, geo_node_mesh_primitive_plane_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_plane_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
new file mode 100644
index 00000000000..e164ad247a3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -0,0 +1,131 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_mesh_primitive_uv_sphere_in[] = {
+ {SOCK_INT, N_("Segments"), 32, 0.0f, 0.0f, 0.0f, 3, 1024},
+ {SOCK_INT, N_("Rings"), 16, 0.0f, 0.0f, 0.0f, 3, 1024},
+ {SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_primitive_uv_sphere_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static int sphere_vert_total(const int segments, const int rings)
+{
+ return segments * (rings - 1) + 2;
+}
+
+static int sphere_edge_total(const int segments, const int rings)
+{
+ return segments * (rings * 2 - 1);
+}
+
+static int sphere_corner_total(const int segments, const int rings)
+{
+ const int quad_corners = 4 * segments * (rings - 2);
+ const int tri_corners = 3 * segments * 2;
+ return quad_corners + tri_corners;
+}
+
+static int sphere_face_total(const int segments, const int rings)
+{
+ const int quads = segments * (rings - 2);
+ const int triangles = segments * 2;
+ return quads + triangles;
+}
+
+static Mesh *create_uv_sphere_mesh_bmesh(const float3 location,
+ const float3 rotation,
+ const float radius,
+ const int segments,
+ const int rings)
+{
+ float4x4 transform;
+ loc_eul_size_to_mat4(transform.values, location, rotation, float3(radius));
+
+ const BMeshCreateParams bmcp = {true};
+ const BMAllocTemplate allocsize = {sphere_vert_total(segments, rings),
+ sphere_edge_total(segments, rings),
+ sphere_corner_total(segments, rings),
+ sphere_face_total(segments, rings)};
+ BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+
+ BMO_op_callf(bm,
+ BMO_FLAG_DEFAULTS,
+ "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
+ segments,
+ rings,
+ radius,
+ transform.values,
+ true);
+
+ Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr);
+ BM_mesh_free(bm);
+
+ return mesh;
+}
+
+static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
+{
+ const int segments_num = params.extract_input<int>("Segments");
+ const int rings_num = params.extract_input<int>("Rings");
+ if (segments_num < 3 || rings_num < 3) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const float radius = params.extract_input<float>("Radius");
+ const float3 location = params.extract_input<float3>("Location");
+ const float3 rotation = params.extract_input<float3>("Rotation");
+
+ Mesh *mesh = create_uv_sphere_mesh_bmesh(location, rotation, radius, segments_num, rings_num);
+ params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_primitive_uv_sphere()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_mesh_primitive_uv_sphere_in, geo_node_mesh_primitive_uv_sphere_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index 1bc280c4bb7..4795970377a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -92,18 +92,17 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
return {looptris, looptris_len};
}
-static int sample_mesh_surface(const Mesh &mesh,
- const float4x4 &transform,
- const float base_density,
- const FloatReadAttribute *density_factors,
- const int seed,
- Vector<float3> &r_positions,
- Vector<float3> &r_bary_coords,
- Vector<int> &r_looptri_indices)
+static void sample_mesh_surface(const Mesh &mesh,
+ const float4x4 &transform,
+ const float base_density,
+ const FloatReadAttribute *density_factors,
+ const int seed,
+ Vector<float3> &r_positions,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices)
{
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
- int points_len = 0;
for (const int looptri_index : looptris.index_range()) {
const MLoopTri &looptri = looptris[looptri_index];
const int v0_loop = looptri.tri[0];
@@ -140,20 +139,17 @@ static int sample_mesh_surface(const Mesh &mesh,
r_positions.append(point_pos);
r_bary_coords.append(bary_coord);
r_looptri_indices.append(looptri_index);
- points_len++;
}
}
- return points_len;
}
-BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_array,
+BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_all,
const int initial_points_len)
{
KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len);
int i_point = 0;
- for (const int i_instance : positions_array.index_range()) {
- Span<float3> positions = positions_array[i_instance];
+ for (const Vector<float3> &positions : positions_all) {
for (const float3 position : positions) {
BLI_kdtree_3d_insert(kdtree, i_point, position);
i_point++;
@@ -164,7 +160,8 @@ BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_array
}
BLI_NOINLINE static void update_elimination_mask_for_close_points(
- Span<Vector<float3>> positions_array,
+ Span<Vector<float3>> positions_all,
+ Span<int> instance_start_offsets,
const float minimum_distance,
MutableSpan<bool> elimination_mask,
const int initial_points_len)
@@ -173,26 +170,27 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
return;
}
- KDTree_3d *kdtree = build_kdtree(positions_array, initial_points_len);
+ KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len);
/* The elimination mask is a flattened array for every point,
* so keep track of the index to it separately. */
- int i_point = 0;
- for (Span<float3> positions : positions_array) {
- for (const float3 position : positions) {
- if (elimination_mask[i_point]) {
- i_point++;
+ for (const int i_instance : positions_all.index_range()) {
+ Span<float3> positions = positions_all[i_instance];
+ const int offset = instance_start_offsets[i_instance];
+
+ for (const int i : positions.index_range()) {
+ if (elimination_mask[offset + i]) {
continue;
}
struct CallbackData {
int index;
MutableSpan<bool> elimination_mask;
- } callback_data = {i_point, elimination_mask};
+ } callback_data = {offset + i, elimination_mask};
BLI_kdtree_3d_range_search_cb(
kdtree,
- position,
+ positions[i],
minimum_distance,
[](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
@@ -202,8 +200,6 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
return true;
},
&callback_data);
-
- i_point++;
}
}
BLI_kdtree_3d_free(kdtree);
@@ -233,8 +229,8 @@ BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
- const float probablity = attribute_math::mix3<float>(
- bary_coord, v0_density_factor, v1_density_factor, v2_density_factor);
+ const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
+ v2_density_factor * bary_coord.z;
const float hash = BLI_hash_int_01(bary_coord.hash());
if (hash > probablity) {
@@ -314,6 +310,23 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
}
template<typename T>
+BLI_NOINLINE static void interpolate_attribute_polygon(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<T> data_in,
+ MutableSpan<T> data_out)
+{
+ BLI_assert(data_in.size() == mesh.totpoly);
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : data_out.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const int poly_index = looptri.poly;
+ data_out[i] = data_in[poly_index];
+ }
+}
+
+template<typename T>
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
@@ -331,6 +344,10 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
mesh, bary_coords, looptri_indices, source_span, output_span);
break;
}
+ case ATTR_DOMAIN_POLYGON: {
+ interpolate_attribute_polygon<T>(mesh, looptri_indices, source_span, output_span);
+ break;
+ }
default: {
/* Not supported currently. */
return;
@@ -339,9 +356,9 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
}
BLI_NOINLINE static void interpolate_existing_attributes(
- Span<GeometryInstanceGroup> sets,
- Span<int> group_start_indices,
- Map<std::string, AttributeKind> &attributes,
+ Span<GeometryInstanceGroup> set_groups,
+ Span<int> instance_start_offsets,
+ const Map<std::string, AttributeKind> &attributes,
GeometryComponent &component,
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
@@ -352,70 +369,64 @@ BLI_NOINLINE static void interpolate_existing_attributes(
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
attribute_name, ATTR_DOMAIN_POINT, output_data_type);
- BLI_assert(attribute_out);
if (!attribute_out) {
continue;
}
- attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
- using T = decltype(dummy);
+ fn::GMutableSpan out_span = attribute_out->get_span_for_write_only();
- MutableSpan<T> out_span = attribute_out->get_span_for_write_only<T>();
-
- int i_set_with_mesh = 0;
- int i_instance = 0;
- for (const GeometryInstanceGroup &set_group : sets) {
- const GeometrySet &set = set_group.geometry_set;
- if (!set.has_mesh()) {
- continue;
- }
- const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *source_component.get_for_read();
-
- /* Use a dummy read without specifying a domain or data type in order to
- * get the existing attribute's domain. Interpolation is done manually based
- * on the bary coords in #interpolate_attribute. */
- ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
- attribute_name);
- if (!dummy_attribute) {
- i_instance += set_group.transforms.size();
- i_set_with_mesh++;
- continue;
- }
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *source_component.get_for_read();
+
+ /* Use a dummy read without specifying a domain or data type in order to
+ * get the existing attribute's domain. Interpolation is done manually based
+ * on the bary coords in #interpolate_attribute. */
+ ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
+ attribute_name);
+ if (!dummy_attribute) {
+ i_instance += set_group.transforms.size();
+ continue;
+ }
- const AttributeDomain source_domain = dummy_attribute->domain();
- ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
- attribute_name, source_domain, output_data_type, nullptr);
- BLI_assert(source_attribute);
- Span<T> source_span = source_attribute->get_span<T>();
+ const AttributeDomain source_domain = dummy_attribute->domain();
+ ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
+ attribute_name, source_domain, output_data_type, nullptr);
+ if (!source_attribute) {
+ i_instance += set_group.transforms.size();
+ continue;
+ }
+ fn::GSpan source_span = source_attribute->get_span();
- if (!source_attribute) {
- i_instance += set_group.transforms.size();
- i_set_with_mesh++;
- continue;
- }
+ attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
+ using T = decltype(dummy);
- int i_point = group_start_indices[i_set_with_mesh];
for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
- Span<float3> bary_coords = bary_coords_array[i_instance].as_span();
- Span<int> looptri_indices = looptri_indices_array[i_instance].as_span();
+ const int offset = instance_start_offsets[i_instance];
+ Span<float3> bary_coords = bary_coords_array[i_instance];
+ Span<int> looptri_indices = looptri_indices_array[i_instance];
+
+ MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size());
+ interpolate_attribute<T>(mesh,
+ bary_coords,
+ looptri_indices,
+ source_domain,
+ source_span.typed<T>(),
+ instance_span);
- MutableSpan<T> instance_span = out_span.slice(i_point, bary_coords.size());
- interpolate_attribute<T>(
- mesh, bary_coords, looptri_indices, source_domain, source_span, instance_span);
-
- i_point += bary_coords.size();
i_instance++;
}
- i_set_with_mesh++;
- }
- });
+ });
+ }
attribute_out.apply_span_and_save();
}
}
BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup> sets,
+ Span<int> instance_start_offsets,
GeometryComponent &component,
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
@@ -427,28 +438,29 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- MutableSpan<int> ids_full = id_attribute->get_span_for_write_only<int>();
- MutableSpan<float3> normals_full = normal_attribute->get_span_for_write_only<float3>();
- MutableSpan<float3> rotations_full = rotation_attribute->get_span_for_write_only<float3>();
+ MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>();
+ MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>();
+ MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>();
- int i_point = 0;
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : sets) {
const GeometrySet &set = set_group.geometry_set;
- if (!set.has_mesh()) {
- continue;
- }
-
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *component.get_for_read();
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
- Span<float3> bary_coords = bary_coords_array[i_instance].as_span();
- Span<int> looptri_indices = looptri_indices_array[i_instance].as_span();
- MutableSpan<int> ids = ids_full.slice(i_point, bary_coords.size());
- MutableSpan<float3> normals = normals_full.slice(i_point, bary_coords.size());
- MutableSpan<float3> rotations = rotations_full.slice(i_point, bary_coords.size());
+ for (const float4x4 &transform : set_group.transforms) {
+ const int offset = instance_start_offsets[i_instance];
+
+ Span<float3> bary_coords = bary_coords_array[i_instance];
+ Span<int> looptri_indices = looptri_indices_array[i_instance];
+ MutableSpan<int> ids = result_ids.slice(offset, bary_coords.size());
+ MutableSpan<float3> normals = result_normals.slice(offset, bary_coords.size());
+ MutableSpan<float3> rotations = result_rotations.slice(offset, bary_coords.size());
+
+ /* Use one matrix multiplication per point instead of three (for each triangle corner). */
+ float rotation_matrix[3][3];
+ mat4_to_rot(rotation_matrix, transform.values);
for (const int i : bary_coords.index_range()) {
const int looptri_index = looptri_indices[i];
@@ -458,17 +470,17 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
const int v0_index = mesh.mloop[looptri.tri[0]].v;
const int v1_index = mesh.mloop[looptri.tri[1]].v;
const int v2_index = mesh.mloop[looptri.tri[2]].v;
- const float3 v0_pos = mesh.mvert[v0_index].co;
- const float3 v1_pos = mesh.mvert[v1_index].co;
- const float3 v2_pos = mesh.mvert[v2_index].co;
+ const float3 v0_pos = float3(mesh.mvert[v0_index].co);
+ const float3 v1_pos = float3(mesh.mvert[v1_index].co);
+ const float3 v2_pos = float3(mesh.mvert[v2_index].co);
- ids[i] = (int)(bary_coord.hash()) + (uint64_t)looptri_index;
+ ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index);
normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
+ mul_m3_v3(rotation_matrix, normals[i]);
rotations[i] = normal_to_euler_rotation(normals[i]);
}
i_instance++;
- i_point += bary_coords.size();
}
}
@@ -478,172 +490,239 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
}
BLI_NOINLINE static void add_remaining_point_attributes(
- Span<GeometryInstanceGroup> sets,
- Span<int> group_start_indices,
- Map<std::string, AttributeKind> &attributes,
+ Span<GeometryInstanceGroup> set_groups,
+ Span<int> instance_start_offsets,
+ const Map<std::string, AttributeKind> &attributes,
GeometryComponent &component,
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
{
- interpolate_existing_attributes(
- sets, group_start_indices, attributes, component, bary_coords_array, looptri_indices_array);
- compute_special_attributes(sets, component, bary_coords_array, looptri_indices_array);
+ interpolate_existing_attributes(set_groups,
+ instance_start_offsets,
+ attributes,
+ component,
+ bary_coords_array,
+ looptri_indices_array);
+ compute_special_attributes(
+ set_groups, instance_start_offsets, component, bary_coords_array, looptri_indices_array);
+}
+
+static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
+ const StringRef density_attribute_name,
+ const float density,
+ const int seed,
+ MutableSpan<Vector<float3>> positions_all,
+ MutableSpan<Vector<float3>> bary_coords_all,
+ MutableSpan<Vector<int>> looptri_indices_all)
+{
+ /* If there is an attribute name, the default value for the densities should be zero so that
+ * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
+ * factors. */
+ const bool use_one_default = density_attribute_name.is_empty();
+
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
+ const Mesh &mesh = *component.get_for_read();
+ for (const float4x4 &transform : set_group.transforms) {
+ Vector<float3> &positions = positions_all[i_instance];
+ Vector<float3> &bary_coords = bary_coords_all[i_instance];
+ Vector<int> &looptri_indices = looptri_indices_all[i_instance];
+ sample_mesh_surface(mesh,
+ transform,
+ density,
+ &density_factors,
+ seed,
+ positions,
+ bary_coords,
+ looptri_indices);
+ i_instance++;
+ }
+ }
+}
+
+static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_groups,
+ const StringRef density_attribute_name,
+ const float density,
+ const int seed,
+ const float minimum_distance,
+ MutableSpan<Vector<float3>> positions_all,
+ MutableSpan<Vector<float3>> bary_coords_all,
+ MutableSpan<Vector<int>> looptri_indices_all)
+{
+ Array<int> instance_start_offsets(positions_all.size());
+ int initial_points_len = 0;
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ for (const float4x4 &transform : set_group.transforms) {
+ Vector<float3> &positions = positions_all[i_instance];
+ Vector<float3> &bary_coords = bary_coords_all[i_instance];
+ Vector<int> &looptri_indices = looptri_indices_all[i_instance];
+ sample_mesh_surface(
+ mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices);
+
+ instance_start_offsets[i_instance] = initial_points_len;
+ initial_points_len += positions.size();
+ i_instance++;
+ }
+ }
+
+ /* If there is an attribute name, the default value for the densities should be zero so that
+ * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
+ * factors. */
+ const bool use_one_default = density_attribute_name.is_empty();
+
+ /* Unlike the other result arrays, the elimination mask in stored as a flat array for every
+ * point, in order to simplify culling points from the KDTree (which needs to know about all
+ * points at once). */
+ Array<bool> elimination_mask(initial_points_len, false);
+ update_elimination_mask_for_close_points(positions_all,
+ instance_start_offsets,
+ minimum_distance,
+ elimination_mask,
+ initial_points_len);
+
+ i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
+
+ for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ Vector<float3> &positions = positions_all[i_instance];
+ Vector<float3> &bary_coords = bary_coords_all[i_instance];
+ Vector<int> &looptri_indices = looptri_indices_all[i_instance];
+
+ const int offset = instance_start_offsets[i_instance];
+ update_elimination_mask_based_on_density_factors(
+ mesh,
+ density_factors,
+ bary_coords,
+ looptri_indices,
+ elimination_mask.as_mutable_span().slice(offset, positions.size()));
+
+ eliminate_points_based_on_mask(elimination_mask.as_span().slice(offset, positions.size()),
+ positions,
+ bary_coords,
+ looptri_indices);
+
+ i_instance++;
+ }
+ }
}
static void geo_node_point_distribute_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- GeometrySet geometry_set_out;
const GeometryNodePointDistributeMode distribute_method =
static_cast<GeometryNodePointDistributeMode>(params.node().custom1);
- if (!geometry_set.has_mesh() && !geometry_set.has_instances()) {
- params.error_message_add(NodeWarningType::Error, "Geometry must contain a mesh.");
- params.set_output("Geometry", std::move(geometry_set_out));
- return;
- }
-
+ const int seed = params.get_input<int>("Seed");
const float density = params.extract_input<float>("Density Max");
const std::string density_attribute_name = params.extract_input<std::string>(
"Density Attribute");
if (density <= 0.0f) {
- params.set_output("Geometry", std::move(geometry_set_out));
+ params.set_output("Geometry", GeometrySet());
return;
}
- const int seed = params.get_input<int>("Seed");
-
- Vector<GeometryInstanceGroup> sets = bke::geometry_set_gather_instances(geometry_set);
- int instances_len = 0;
- for (GeometryInstanceGroup set_group : sets) {
- instances_len += set_group.transforms.size();
+ Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set);
+ if (set_groups.is_empty()) {
+ params.set_output("Geometry", GeometrySet());
+ return;
}
- /* Store data per-instance in order to simplify attribute access after the scattering,
- * and to make the point elimination simpler for the poisson disk mode. Node that some
- * vectors will be empty if any instances don't contain mesh data. */
- Array<Vector<float3>> positions_array(instances_len);
- Array<Vector<float3>> bary_coords_array(instances_len);
- Array<Vector<int>> looptri_indices_array(instances_len);
-
- int initial_points_len = 0;
- int i_instance = 0;
- for (const GeometryInstanceGroup &set_group : sets) {
- const GeometrySet &set = set_group.geometry_set;
+ /* Remove any set inputs that don't contain a mesh, to avoid checking later on. */
+ for (int i = set_groups.size() - 1; i >= 0; i--) {
+ const GeometrySet &set = set_groups[i].geometry_set;
if (!set.has_mesh()) {
- continue;
+ set_groups.remove_and_reorder(i);
}
+ }
- const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *component.get_for_read();
- for (const float4x4 &transform : set_group.transforms) {
- Vector<float3> &positions = positions_array[i_instance];
- Vector<float3> &bary_coords = bary_coords_array[i_instance];
- Vector<int> &looptri_indices = looptri_indices_array[i_instance];
-
- switch (distribute_method) {
- case GEO_NODE_POINT_DISTRIBUTE_RANDOM: {
- const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
- density_attribute_name, ATTR_DOMAIN_CORNER, 1.0f);
- initial_points_len += sample_mesh_surface(mesh,
- transform,
- density,
- &density_factors,
- seed,
- positions,
- bary_coords,
- looptri_indices);
- break;
- }
- case GEO_NODE_POINT_DISTRIBUTE_POISSON:
- initial_points_len += sample_mesh_surface(
- mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices);
- break;
- }
- i_instance++;
- }
+ if (set_groups.is_empty()) {
+ params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
+ params.set_output("Geometry", GeometrySet());
+ return;
}
- if (distribute_method == GEO_NODE_POINT_DISTRIBUTE_POISSON) {
- /* Unlike the other result arrays, the elimination mask in stored as a flat array for every
- * point, in order to simplify culling points from the KDTree (which needs to know about all
- * points at once). */
- Array<bool> elimination_mask(initial_points_len, false);
- const float minimum_distance = params.get_input<float>("Distance Min");
- update_elimination_mask_for_close_points(
- positions_array, minimum_distance, elimination_mask, initial_points_len);
-
- int i_point = 0;
- i_instance = 0;
- for (const GeometryInstanceGroup &set_group : sets) {
- const GeometrySet &set = set_group.geometry_set;
- if (!set.has_mesh()) {
- continue;
- }
+ int instances_len = 0;
+ for (GeometryInstanceGroup &set_group : set_groups) {
+ instances_len += set_group.transforms.size();
+ }
- const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *component.get_for_read();
- const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
- density_attribute_name, ATTR_DOMAIN_CORNER, 1.0f);
-
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
- Vector<float3> &positions = positions_array[i_instance];
- Vector<float3> &bary_coords = bary_coords_array[i_instance];
- Vector<int> &looptri_indices = looptri_indices_array[i_instance];
-
- update_elimination_mask_based_on_density_factors(
- mesh,
- density_factors,
- bary_coords,
- looptri_indices,
- elimination_mask.as_mutable_span().slice(i_point, positions.size()));
-
- /* The positions vector's size is changed, temporarily store the
- * original size to properly advance the elimination mask index. */
- const int initial_positions_size = positions.size();
- eliminate_points_based_on_mask(elimination_mask.as_span().slice(i_point, positions.size()),
- positions,
- bary_coords,
- looptri_indices);
-
- i_point += initial_positions_size;
- i_instance++;
- }
+ /* Store data per-instance in order to simplify attribute access after the scattering,
+ * and to make the point elimination simpler for the poisson disk mode. Note that some
+ * vectors will be empty if any instances don't contain mesh data. */
+ Array<Vector<float3>> positions_all(instances_len);
+ Array<Vector<float3>> bary_coords_all(instances_len);
+ Array<Vector<int>> looptri_indices_all(instances_len);
+
+ switch (distribute_method) {
+ case GEO_NODE_POINT_DISTRIBUTE_RANDOM: {
+ distribute_points_random(set_groups,
+ density_attribute_name,
+ density,
+ seed,
+ positions_all,
+ bary_coords_all,
+ looptri_indices_all);
+ break;
+ }
+ case GEO_NODE_POINT_DISTRIBUTE_POISSON: {
+ const float minimum_distance = params.extract_input<float>("Distance Min");
+ distribute_points_poisson_disk(set_groups,
+ density_attribute_name,
+ density,
+ seed,
+ minimum_distance,
+ positions_all,
+ bary_coords_all,
+ looptri_indices_all);
+ break;
}
}
int final_points_len = 0;
- Array<int> group_start_indices(sets.size());
- for (const int i : positions_array.index_range()) {
- Vector<float3> &positions = positions_array[i];
- group_start_indices[i] = final_points_len;
+ Array<int> instance_start_offsets(set_groups.size());
+ for (const int i : positions_all.index_range()) {
+ Vector<float3> &positions = positions_all[i];
+ instance_start_offsets[i] = final_points_len;
final_points_len += positions.size();
}
PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len);
- int i_point = 0;
- for (Vector<float3> &positions : positions_array) {
- memcpy(pointcloud->co + i_point, positions.data(), sizeof(float3) * positions.size());
- i_point += positions.size();
+ for (const int instance_index : positions_all.index_range()) {
+ const int offset = instance_start_offsets[instance_index];
+ Span<float3> positions = positions_all[instance_index];
+ memcpy(pointcloud->co + offset, positions.data(), sizeof(float3) * positions.size());
}
- MutableSpan(pointcloud->radius, pointcloud->totpoint).fill(0.05f);
+ uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
+ GeometrySet geometry_set_out = GeometrySet::create_with_pointcloud(pointcloud);
PointCloudComponent &point_component =
geometry_set_out.get_component_for_write<PointCloudComponent>();
- point_component.replace(pointcloud);
Map<std::string, AttributeKind> attributes;
bke::gather_attribute_info(
- attributes, {GeometryComponentType::Mesh}, sets, {"position", "normal", "id"});
- add_remaining_point_attributes(sets,
- group_start_indices,
+ attributes, {GEO_COMPONENT_TYPE_MESH}, set_groups, {"position", "normal", "id"});
+ add_remaining_point_attributes(set_groups,
+ instance_start_offsets,
attributes,
point_component,
- bary_coords_array,
- looptri_indices_array);
+ bary_coords_all,
+ looptri_indices_all);
params.set_output("Geometry", std::move(geometry_set_out));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index 669b5ee4614..dbbb73bd36d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -103,7 +103,7 @@ static void get_instanced_data__collection(
if (BLI_listbase_is_empty(&collection->children) &&
BLI_listbase_is_empty(&collection->gobject)) {
- params.error_message_add(NodeWarningType::Info, "Collection is empty.");
+ params.error_message_add(NodeWarningType::Info, TIP_("Collection is empty"));
return;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
index cb3cd012c77..015f4cd38e7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
@@ -46,6 +46,9 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
{
OutputAttributePtr position_attribute = component.attribute_try_get_for_output(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ if (!position_attribute) {
+ return;
+ }
ReadAttributePtr attribute = params.get_input_attribute(
"Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
if (!attribute) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc
index 2a0cb727cd6..06c5586a3ff 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc
@@ -25,20 +25,20 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_subdivision_surface_simple_in[] = {
+static bNodeSocketTemplate geo_node_subdivide_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6},
{-1, ""},
};
-static bNodeSocketTemplate geo_node_subdivision_surface_simple_out[] = {
+static bNodeSocketTemplate geo_node_subdivide_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
-static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params)
+static void geo_node_subdivide_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -49,7 +49,7 @@ static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params)
#ifndef WITH_OPENSUBDIV
params.error_message_add(NodeWarningType::Error,
- "Disabled, Blender was built without OpenSubdiv");
+ TIP_("Disabled, Blender was built without OpenSubdiv"));
params.set_output("Geometry", std::move(geometry_set));
return;
#endif
@@ -91,7 +91,8 @@ static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params)
Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
BKE_mesh_calc_normals(mesh_out);
- geometry_set.replace_mesh(mesh_out);
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out);
BKE_subdiv_free(subdiv);
@@ -99,17 +100,12 @@ static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params)
}
} // namespace blender::nodes
-void register_node_type_geo_subdivision_surface_simple()
+void register_node_type_geo_subdivide()
{
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_SUBDIVISION_SURFACE_SIMPLE,
- "Simple Subdivision Surface",
- NODE_CLASS_GEOMETRY,
- 0);
- node_type_socket_templates(
- &ntype, geo_node_subdivision_surface_simple_in, geo_node_subdivision_surface_simple_out);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_simple_exec;
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE, "Subdivide", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_subdivide_in, geo_node_subdivide_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 47304a0de68..b14a512ce28 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -69,7 +69,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
#else
const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 30);
- /* Only process subdivion if level is greater than 0. */
+ /* Only process subdivision if level is greater than 0. */
if (subdiv_level == 0) {
params.set_output("Geometry", std::move(geometry_set));
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 539a7551be9..ef6f0be40f2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -57,14 +57,16 @@ static bool use_translate(const float3 rotation, const float3 scale)
return true;
}
-static void transform_mesh(Mesh *mesh,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
+void transform_mesh(Mesh *mesh,
+ const float3 translation,
+ const float3 rotation,
+ const float3 scale)
{
/* Use only translation if rotation and scale are zero. */
if (use_translate(rotation, scale)) {
- BKE_mesh_translate(mesh, translation, true);
+ if (!translation.is_zero()) {
+ BKE_mesh_translate(mesh, translation, true);
+ }
}
else {
float mat[4][4];
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index f5a0e14f18b..36c64b00f47 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -16,523 +16,261 @@
#include "NOD_derived_node_tree.hh"
-#include "BLI_dot_export.hh"
-
-#define UNINITIALIZED_ID UINT32_MAX
-
namespace blender::nodes {
-static const NodeTreeRef &get_tree_ref(NodeTreeRefMap &node_tree_refs, bNodeTree *btree)
+/* Construct a new derived node tree for a given root node tree. The generated derived node tree
+ * does not own the used node tree refs (so that those can be used by others as well). The caller
+ * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
+ * derived node tree. */
+DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
{
- return *node_tree_refs.lookup_or_add_cb(btree,
- [&]() { return std::make_unique<NodeTreeRef>(btree); });
+ /* Construct all possible contexts immediately. This is significantly cheaper than inlining all
+ * node groups. If it still becomes a performance issue in the future, contexts could be
+ * constructed lazily when they are needed. */
+ root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs);
}
-DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : btree_(btree)
+DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
+ const NodeRef *parent_node,
+ bNodeTree &btree,
+ NodeTreeRefMap &node_tree_refs)
{
- BLI_assert(btree != nullptr);
-
- const NodeTreeRef &main_tree_ref = get_tree_ref(node_tree_refs, btree);
- used_node_tree_refs_.add_new(&main_tree_ref);
-
- Vector<DNode *> all_nodes;
- Vector<DGroupInput *> all_group_inputs;
- Vector<DParentNode *> all_parent_nodes;
-
- this->insert_nodes_and_links_in_id_order(main_tree_ref, nullptr, all_nodes);
- this->expand_groups(all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs);
- this->relink_and_remove_muted_nodes(all_nodes);
- this->remove_expanded_group_interfaces(all_nodes);
- this->remove_unused_group_inputs(all_group_inputs);
- this->store_in_this_and_init_ids(
- std::move(all_nodes), std::move(all_group_inputs), std::move(all_parent_nodes));
-}
-
-BLI_NOINLINE void DerivedNodeTree::insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref,
- DParentNode *parent,
- Vector<DNode *> &all_nodes)
-{
- Array<DSocket *, 64> sockets_map(tree_ref.sockets().size());
-
- /* Insert nodes. */
- for (const NodeRef *node_ref : tree_ref.nodes()) {
- DNode &node = this->create_node(*node_ref, parent, sockets_map);
- all_nodes.append(&node);
- }
-
- /* Insert links. */
- for (const NodeRef *node_ref : tree_ref.nodes()) {
- for (const InputSocketRef *to_socket_ref : node_ref->inputs()) {
- DInputSocket *to_socket = static_cast<DInputSocket *>(sockets_map[to_socket_ref->id()]);
- for (const OutputSocketRef *from_socket_ref : to_socket_ref->linked_sockets()) {
- DOutputSocket *from_socket = static_cast<DOutputSocket *>(
- sockets_map[from_socket_ref->id()]);
- to_socket->linked_sockets_.append(from_socket);
- from_socket->linked_sockets_.append(to_socket);
+ DTreeContext &context = *allocator_.construct<DTreeContext>().release();
+ context.parent_context_ = parent_context;
+ context.parent_node_ = parent_node;
+ context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
+ used_node_tree_refs_.add(context.tree_);
+
+ for (const NodeRef *node : context.tree_->nodes()) {
+ if (node->is_group_node()) {
+ bNode *bnode = node->bnode();
+ bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
+ if (child_btree != nullptr) {
+ DTreeContext &child = this->construct_context_recursively(
+ &context, node, *child_btree, node_tree_refs);
+ context.children_.add_new(node, &child);
}
}
}
+
+ return context;
}
-DNode &DerivedNodeTree::create_node(const NodeRef &node_ref,
- DParentNode *parent,
- MutableSpan<DSocket *> r_sockets_map)
+DerivedNodeTree::~DerivedNodeTree()
{
- DNode &node = *allocator_.construct<DNode>();
- node.node_ref_ = &node_ref;
- node.parent_ = parent;
- node.id_ = UNINITIALIZED_ID;
-
- node.inputs_ = allocator_.construct_elements_and_pointer_array<DInputSocket>(
- node_ref.inputs().size());
- node.outputs_ = allocator_.construct_elements_and_pointer_array<DOutputSocket>(
- node_ref.outputs().size());
-
- for (int i : node.inputs_.index_range()) {
- const InputSocketRef &socket_ref = node_ref.input(i);
- DInputSocket &socket = *node.inputs_[i];
- socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT;
- socket.id_ = UNINITIALIZED_ID;
- socket.node_ = &node;
- socket.socket_ref_ = &socket_ref;
-
- r_sockets_map[socket_ref.id()] = &socket;
- }
-
- for (int i : node.outputs_.index_range()) {
- const OutputSocketRef &socket_ref = node_ref.output(i);
- DOutputSocket &socket = *node.outputs_[i];
-
- socket.id_ = UNINITIALIZED_ID;
- socket.node_ = &node;
- socket.socket_ref_ = &socket_ref;
-
- r_sockets_map[socket_ref.id()] = &socket;
- }
-
- return node;
+ /* Has to be destructed manually, because the context info is allocated in a linear allocator. */
+ this->destruct_context_recursively(root_context_);
}
-BLI_NOINLINE void DerivedNodeTree::expand_groups(Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs)
+void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
{
- for (int i = 0; i < all_nodes.size(); i++) {
- DNode &node = *all_nodes[i];
- if (node.node_ref_->is_group_node()) {
- /* Muted nodes are relinked in a separate step. */
- if (!node.node_ref_->is_muted()) {
- this->expand_group_node(
- node, all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs);
- }
- }
+ for (DTreeContext *child : context->children_.values()) {
+ this->destruct_context_recursively(child);
}
+ context->~DTreeContext();
}
-BLI_NOINLINE void DerivedNodeTree::expand_group_node(DNode &group_node,
- Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs)
+/* Returns true if there are any cycles in the node tree. */
+bool DerivedNodeTree::has_link_cycles() const
{
- const NodeRef &group_node_ref = *group_node.node_ref_;
- BLI_assert(group_node_ref.is_group_node());
-
- bNodeTree *btree = reinterpret_cast<bNodeTree *>(group_node_ref.bnode()->id);
- if (btree == nullptr) {
- return;
+ for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
+ if (tree_ref->has_link_cycles()) {
+ return true;
+ }
}
-
- const NodeTreeRef &group_ref = get_tree_ref(node_tree_refs, btree);
- used_node_tree_refs_.add(&group_ref);
-
- DParentNode &parent = *allocator_.construct<DParentNode>();
- parent.id_ = all_parent_nodes.append_and_get_index(&parent);
- parent.parent_ = group_node.parent_;
- parent.node_ref_ = &group_node_ref;
-
- this->insert_nodes_and_links_in_id_order(group_ref, &parent, all_nodes);
- Span<DNode *> new_nodes_by_id = all_nodes.as_span().take_back(group_ref.nodes().size());
-
- this->create_group_inputs_for_unlinked_inputs(group_node, all_group_inputs);
- this->relink_group_inputs(group_ref, new_nodes_by_id, group_node);
- this->relink_group_outputs(group_ref, new_nodes_by_id, group_node);
+ return false;
}
-BLI_NOINLINE void DerivedNodeTree::create_group_inputs_for_unlinked_inputs(
- DNode &node, Vector<DGroupInput *> &all_group_inputs)
+/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
+void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
- for (DInputSocket *input_socket : node.inputs_) {
- if (input_socket->is_linked()) {
- continue;
- }
-
- DGroupInput &group_input = *allocator_.construct<DGroupInput>();
- group_input.id_ = UNINITIALIZED_ID;
- group_input.socket_ref_ = &input_socket->socket_ref();
- group_input.parent_ = node.parent_;
-
- group_input.linked_sockets_.append(input_socket);
- input_socket->linked_group_inputs_.append(&group_input);
- all_group_inputs.append(&group_input);
- }
+ this->foreach_node_in_context_recursive(*root_context_, callback);
}
-BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node)
+void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
+ FunctionRef<void(DNode)> callback) const
{
- Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput");
- if (node_refs.size() == 0) {
- return;
+ for (const NodeRef *node_ref : context.tree_->nodes()) {
+ callback(DNode(&context, node_ref));
}
- /* TODO: Pick correct group input node if there are more than one. */
- const NodeRef &input_node_ref = *node_refs[0];
- DNode &input_node = *nodes_by_id[input_node_ref.id()];
-
- int input_amount = group_node.inputs().size();
- BLI_assert(input_amount == input_node_ref.outputs().size() - 1);
-
- for (int input_index : IndexRange(input_amount)) {
- DInputSocket *outside_group = group_node.inputs_[input_index];
- DOutputSocket *inside_group = input_node.outputs_[input_index];
-
- for (DOutputSocket *outside_connected : outside_group->linked_sockets_) {
- outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
- }
-
- for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) {
- outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
- }
-
- for (DInputSocket *inside_connected : inside_group->linked_sockets_) {
- inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
-
- for (DOutputSocket *outside_connected : outside_group->linked_sockets_) {
- inside_connected->linked_sockets_.append(outside_connected);
- outside_connected->linked_sockets_.append(inside_connected);
- }
-
- for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) {
- inside_connected->linked_group_inputs_.append(outside_connected);
- outside_connected->linked_sockets_.append(inside_connected);
- }
- }
-
- inside_group->linked_sockets_.clear();
- outside_group->linked_sockets_.clear();
- outside_group->linked_group_inputs_.clear();
+ for (const DTreeContext *child_context : context.children_.values()) {
+ this->foreach_node_in_context_recursive(*child_context, callback);
}
}
-BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node)
+DOutputSocket DInputSocket::get_corresponding_group_node_output() const
{
- Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput");
- if (node_refs.size() == 0) {
- return;
- }
- /* TODO: Pick correct group output node if there are more than one. */
- const NodeRef &output_node_ref = *node_refs[0];
- DNode &output_node = *nodes_by_id[output_node_ref.id()];
-
- int output_amount = group_node.outputs().size();
- BLI_assert(output_amount == output_node_ref.inputs().size() - 1);
-
- for (int output_index : IndexRange(output_amount)) {
- DOutputSocket *outside_group = group_node.outputs_[output_index];
- DInputSocket *inside_group = output_node.inputs_[output_index];
-
- for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
- outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
- }
-
- for (DOutputSocket *inside_connected : inside_group->linked_sockets_) {
- inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
-
- for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
- inside_connected->linked_sockets_.append(outside_connected);
- outside_connected->linked_sockets_.append(inside_connected);
- }
- }
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_output_node());
+ BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1);
- for (DGroupInput *inside_connected : inside_group->linked_group_inputs_) {
- inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
+ const DTreeContext *parent_context = context_->parent_context();
+ const NodeRef *parent_node = context_->parent_node();
+ BLI_assert(parent_context != nullptr);
+ BLI_assert(parent_node != nullptr);
- for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
- inside_connected->linked_sockets_.append(outside_connected);
- outside_connected->linked_group_inputs_.append(inside_connected);
- }
- }
-
- outside_group->linked_sockets_.clear();
- inside_group->linked_sockets_.clear();
- }
+ const int socket_index = socket_ref_->index();
+ return {parent_context, &parent_node->output(socket_index)};
}
-BLI_NOINLINE void DerivedNodeTree::remove_expanded_group_interfaces(Vector<DNode *> &all_nodes)
+Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const
{
- int index = 0;
- while (index < all_nodes.size()) {
- DNode &node = *all_nodes[index];
- const NodeRef &node_ref = *node.node_ref_;
- if (node_ref.is_group_node() ||
- (node.parent_ != nullptr &&
- (node_ref.is_group_input_node() || node_ref.is_group_output_node()))) {
- all_nodes.remove_and_reorder(index);
- node.destruct_with_sockets();
- }
- else {
- index++;
- }
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_node());
+
+ const DTreeContext *child_context = context_->child_context(socket_ref_->node());
+ BLI_assert(child_context != nullptr);
+
+ const NodeTreeRef &child_tree = child_context->tree();
+ Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
+ const int socket_index = socket_ref_->index();
+ Vector<DOutputSocket> sockets;
+ for (const NodeRef *group_input_node : group_input_nodes) {
+ sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index)));
}
+ return sockets;
}
-BLI_NOINLINE void DerivedNodeTree::remove_unused_group_inputs(
- Vector<DGroupInput *> &all_group_inputs)
+DInputSocket DOutputSocket::get_corresponding_group_node_input() const
{
- int index = 0;
- while (index < all_group_inputs.size()) {
- DGroupInput &group_input = *all_group_inputs[index];
- if (group_input.linked_sockets_.is_empty()) {
- all_group_inputs.remove_and_reorder(index);
- group_input.~DGroupInput();
- }
- else {
- index++;
- }
- }
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_input_node());
+ BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1);
+
+ const DTreeContext *parent_context = context_->parent_context();
+ const NodeRef *parent_node = context_->parent_node();
+ BLI_assert(parent_context != nullptr);
+ BLI_assert(parent_node != nullptr);
+
+ const int socket_index = socket_ref_->index();
+ return {parent_context, &parent_node->input(socket_index)};
}
-BLI_NOINLINE void DerivedNodeTree::relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes)
+DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
{
- int index = 0;
- while (index < all_nodes.size()) {
- DNode &node = *all_nodes[index];
- const NodeRef &node_ref = *node.node_ref_;
- if (node_ref.is_muted()) {
- this->relink_muted_node(node);
- all_nodes.remove_and_reorder(index);
- node.destruct_with_sockets();
- }
- else {
- index++;
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_node());
+
+ const DTreeContext *child_context = context_->child_context(socket_ref_->node());
+ BLI_assert(child_context != nullptr);
+
+ const NodeTreeRef &child_tree = child_context->tree();
+ Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
+ const int socket_index = socket_ref_->index();
+ for (const NodeRef *group_output_node : group_output_nodes) {
+ if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) {
+ return {child_context, &group_output_node->input(socket_index)};
}
}
+ return {};
}
-BLI_NOINLINE void DerivedNodeTree::relink_muted_node(DNode &node)
+/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Origin sockets are ones where a node gets its
+ * inputs from. */
+void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback,
+ const bool follow_only_first_incoming_link) const
{
- const bNode &bnode = *node.bnode();
- LISTBASE_FOREACH (const bNodeLink *, internal_link, &bnode.internal_links) {
- BLI_assert(internal_link->fromnode == &bnode);
- BLI_assert(internal_link->tonode == &bnode);
- bNodeSocket *input_bsocket = internal_link->fromsock;
- bNodeSocket *output_bsocket = internal_link->tosock;
-
- /* Find internally linked sockets. */
- DInputSocket *input_socket = nullptr;
- DOutputSocket *output_socket = nullptr;
- for (DInputSocket *socket : node.inputs_) {
- if (socket->bsocket() == input_bsocket) {
- input_socket = socket;
- break;
- }
- }
- for (DOutputSocket *socket : node.outputs_) {
- if (socket->bsocket() == output_bsocket) {
- output_socket = socket;
- break;
+ BLI_assert(*this);
+ Span<const OutputSocketRef *> linked_sockets_to_check = socket_ref_->as_input().linked_sockets();
+ if (follow_only_first_incoming_link) {
+ linked_sockets_to_check = linked_sockets_to_check.take_front(1);
+ }
+ for (const OutputSocketRef *linked_socket : linked_sockets_to_check) {
+ const NodeRef &linked_node = linked_socket->node();
+ DOutputSocket linked_dsocket{context_, linked_socket};
+
+ if (linked_node.is_muted()) {
+ /* If the node is muted, follow the internal links of the node. */
+ for (const InternalLinkRef *internal_link : linked_node.internal_links()) {
+ if (&internal_link->to() == linked_socket) {
+ DInputSocket input_of_muted_node{context_, &internal_link->from()};
+ input_of_muted_node.foreach_origin_socket(callback, true);
+ }
}
}
- BLI_assert(input_socket != nullptr);
- BLI_assert(output_socket != nullptr);
-
- /* Link sockets connected to the input to sockets that are connected to the internally linked
- * output. */
- for (DInputSocket *to_socket : output_socket->linked_sockets_) {
- for (DOutputSocket *from_socket : input_socket->linked_sockets_) {
- from_socket->linked_sockets_.append_non_duplicates(to_socket);
- to_socket->linked_sockets_.append_non_duplicates(from_socket);
+ else if (linked_node.is_group_input_node()) {
+ if (context_->is_root()) {
+ /* This is a group input in the root node group. */
+ callback(linked_dsocket);
}
- for (DGroupInput *group_input : input_socket->linked_group_inputs_) {
- group_input->linked_sockets_.append_non_duplicates(to_socket);
- to_socket->linked_group_inputs_.append_non_duplicates(group_input);
+ else {
+ DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input();
+ if (socket_in_parent_group->is_linked()) {
+ /* Follow the links coming into the corresponding socket on the parent group node. */
+ socket_in_parent_group.foreach_origin_socket(callback);
+ }
+ else {
+ /* The corresponding input on the parent group node is not connected. Therefore, we use
+ * the value of that input socket directly. */
+ callback(socket_in_parent_group);
+ }
}
}
- }
-
- /* Remove remaining links from muted node. */
- for (DInputSocket *to_socket : node.inputs_) {
- for (DOutputSocket *from_socket : to_socket->linked_sockets_) {
- from_socket->linked_sockets_.remove_first_occurrence_and_reorder(to_socket);
- }
- for (DGroupInput *from_group_input : to_socket->linked_group_inputs_) {
- from_group_input->linked_sockets_.remove_first_occurrence_and_reorder(to_socket);
- }
- to_socket->linked_sockets_.clear();
- to_socket->linked_group_inputs_.clear();
- }
- for (DOutputSocket *from_socket : node.outputs_) {
- for (DInputSocket *to_socket : from_socket->linked_sockets_) {
- to_socket->linked_sockets_.remove_first_occurrence_and_reorder(from_socket);
- }
- from_socket->linked_sockets_.clear();
- }
-}
-
-void DNode::destruct_with_sockets()
-{
- for (DInputSocket *socket : inputs_) {
- socket->~DInputSocket();
- }
- for (DOutputSocket *socket : outputs_) {
- socket->~DOutputSocket();
- }
- this->~DNode();
-}
-
-BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids(
- Vector<DNode *> &&all_nodes,
- Vector<DGroupInput *> &&all_group_inputs,
- Vector<DParentNode *> &&all_parent_nodes)
-{
- nodes_by_id_ = std::move(all_nodes);
- group_inputs_ = std::move(all_group_inputs);
- parent_nodes_ = std::move(all_parent_nodes);
-
- for (int node_index : nodes_by_id_.index_range()) {
- DNode *node = nodes_by_id_[node_index];
- node->id_ = node_index;
-
- const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo;
- nodes_by_type_.add(nodetype, node);
-
- for (DInputSocket *socket : node->inputs_) {
- socket->id_ = sockets_by_id_.append_and_get_index(socket);
- input_sockets_.append(socket);
- }
- for (DOutputSocket *socket : node->outputs_) {
- socket->id_ = sockets_by_id_.append_and_get_index(socket);
- output_sockets_.append(socket);
+ else if (linked_node.is_group_node()) {
+ DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket();
+ if (socket_in_group) {
+ if (socket_in_group->is_linked()) {
+ /* Follow the links coming into the group output node of the child node group. */
+ socket_in_group.foreach_origin_socket(callback);
+ }
+ else {
+ /* The output of the child node group is not connected, so we have to get the value from
+ * that socket. */
+ callback(socket_in_group);
+ }
+ }
}
- }
-
- for (int i : group_inputs_.index_range()) {
- group_inputs_[i]->id_ = i;
- }
-}
-
-DerivedNodeTree::~DerivedNodeTree()
-{
- for (DInputSocket *socket : input_sockets_) {
- socket->~DInputSocket();
- }
- for (DOutputSocket *socket : output_sockets_) {
- socket->~DOutputSocket();
- }
- for (DNode *node : nodes_by_id_) {
- node->~DNode();
- }
- for (DGroupInput *group_input : group_inputs_) {
- group_input->~DGroupInput();
- }
- for (DParentNode *parent : parent_nodes_) {
- parent->~DParentNode();
- }
-}
-
-bool DerivedNodeTree::has_link_cycles() const
-{
- for (const NodeTreeRef *tree : used_node_tree_refs_) {
- if (tree->has_link_cycles()) {
- return true;
+ else {
+ /* The normal case: just use the value of a linked output socket. */
+ callback(linked_dsocket);
}
}
- return false;
-}
-
-static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph,
- Map<const DParentNode *, dot::Cluster *> &clusters,
- const DParentNode *parent)
-{
- if (parent == nullptr) {
- return nullptr;
- }
- return clusters.lookup_or_add_cb(parent, [&]() {
- dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent());
- bNodeTree *btree = reinterpret_cast<bNodeTree *>(parent->node_ref().bnode()->id);
- dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " +
- StringRef(btree->id.name + 2));
- new_cluster->set_parent_cluster(parent_cluster);
- return new_cluster;
- });
}
-std::string DerivedNodeTree::to_dot() const
+/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Target sockets are on the nodes that use the value
+ * from this socket. */
+void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const
{
- dot::DirectedGraph digraph;
- digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
-
- Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes;
- Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs;
- Map<const DParentNode *, dot::Cluster *> dot_clusters;
-
- for (const DNode *node : nodes_by_id_) {
- dot::Node &dot_node = digraph.new_node("");
- dot_node.set_background_color("white");
-
- Vector<std::string> input_names;
- for (const DInputSocket *socket : node->inputs()) {
- input_names.append(socket->name());
- }
- Vector<std::string> output_names;
- for (const DOutputSocket *socket : node->outputs()) {
- output_names.append(socket->name());
+ for (const InputSocketRef *linked_socket : socket_ref_->as_output().linked_sockets()) {
+ const NodeRef &linked_node = linked_socket->node();
+ DInputSocket linked_dsocket{context_, linked_socket};
+
+ if (linked_node.is_muted()) {
+ /* If the target node is muted, follow its internal links. */
+ for (const InternalLinkRef *internal_link : linked_node.internal_links()) {
+ if (&internal_link->from() == linked_socket) {
+ DOutputSocket output_of_muted_node{context_, &internal_link->to()};
+ output_of_muted_node.foreach_target_socket(callback);
+ }
+ }
}
-
- dot_nodes.add_new(node,
- dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
-
- dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent());
- dot_node.set_parent_cluster(cluster);
- }
-
- for (const DGroupInput *group_input : group_inputs_) {
- dot::Node &dot_node = digraph.new_node("");
- dot_node.set_background_color("white");
-
- std::string group_input_name = group_input->name();
- dot_group_inputs.add_new(
- group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name}));
-
- dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent());
- dot_node.set_parent_cluster(cluster);
- }
-
- for (const DNode *to_node : nodes_by_id_) {
- dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node);
-
- for (const DInputSocket *to_socket : to_node->inputs()) {
- for (const DOutputSocket *from_socket : to_socket->linked_sockets()) {
- const DNode *from_node = &from_socket->node();
- dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node);
-
- digraph.new_edge(from_dot_node.output(from_socket->index()),
- to_dot_node.input(to_socket->index()));
+ else if (linked_node.is_group_output_node()) {
+ if (context_->is_root()) {
+ /* This is a group output in the root node group. */
+ callback(linked_dsocket);
}
- for (const DGroupInput *group_input : to_socket->linked_group_inputs()) {
- dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input);
-
- digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index()));
+ else {
+ /* Follow the links going out of the group node in the parent node group. */
+ DOutputSocket socket_in_parent_group =
+ linked_dsocket.get_corresponding_group_node_output();
+ socket_in_parent_group.foreach_target_socket(callback);
+ }
+ }
+ else if (linked_node.is_group_node()) {
+ /* Follow the links within the nested node group. */
+ Vector<DOutputSocket> sockets_in_group =
+ linked_dsocket.get_corresponding_group_input_sockets();
+ for (DOutputSocket socket_in_group : sockets_in_group) {
+ socket_in_group.foreach_target_socket(callback);
}
}
+ else {
+ /* The normal case: just use the linked input socket as target. */
+ callback(linked_dsocket);
+ }
}
-
- digraph.set_random_cluster_bgcolors();
- return digraph.to_dot_string();
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 0d46119ab60..dd9d0b6796a 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -71,7 +71,8 @@ void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack
static void node_init_input_index(bNodeSocket *sock, int *index)
{
/* Only consider existing link if from socket is valid! */
- if (sock->link && sock->link->fromsock && sock->link->fromsock->stack_index >= 0) {
+ if (sock->link && !(sock->link->flag & NODE_LINK_MUTED) && sock->link->fromsock &&
+ sock->link->fromsock->stack_index >= 0) {
sock->stack_index = sock->link->fromsock->stack_index;
}
else {
@@ -131,7 +132,7 @@ static struct bNodeStack *setup_stack(bNodeStack *stack,
}
/* don't mess with remote socket stacks, these are initialized by other nodes! */
- if (sock->link) {
+ if (sock->link && !(sock->link->flag & NODE_LINK_MUTED)) {
return ns;
}
@@ -218,7 +219,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* prepare all nodes for execution */
for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) {
node = nodeexec->node = nodelist[n];
- nodeexec->freeexecfunc = node->typeinfo->freeexecfunc;
+ nodeexec->free_exec_fn = node->typeinfo->free_exec_fn;
/* tag inputs */
for (sock = node->inputs.first; sock; sock = sock->next) {
@@ -242,8 +243,8 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
nodeexec->data.preview = context->previews ?
BKE_node_instance_hash_lookup(context->previews, nodekey) :
NULL;
- if (node->typeinfo->initexecfunc) {
- nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey);
+ if (node->typeinfo->init_exec_fn) {
+ nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey);
}
}
@@ -264,8 +265,8 @@ void ntree_exec_end(bNodeTreeExec *exec)
}
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
- if (nodeexec->freeexecfunc) {
- nodeexec->freeexecfunc(nodeexec->data.data);
+ if (nodeexec->free_exec_fn) {
+ nodeexec->free_exec_fn(nodeexec->data.data);
}
}
@@ -323,8 +324,8 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
* If the mute func is not set, assume the node should never be muted,
* and hence execute it!
*/
- if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED)) {
- node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout);
+ if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) {
+ node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout);
}
}
}
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index 806dd10d9bf..de7cbb8cedb 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -48,7 +48,7 @@ typedef struct bNodeExec {
bNodeExecData data;
/** Free function, stored in exec itself to avoid dangling node pointer access. */
- NodeFreeExecFunction freeexecfunc;
+ NodeFreeExecFunction free_exec_fn;
} bNodeExec;
/* Execution Data for each instance of node tree execution */
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index a2e0a4dd6a4..a4fb99a988e 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -20,7 +20,6 @@
#include "DEG_depsgraph_query.h"
-#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
@@ -30,7 +29,7 @@ namespace blender::nodes {
void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
{
- bNodeTree *btree_cow = node_.node_ref().tree().btree();
+ bNodeTree *btree_cow = node_->btree();
BLI_assert(btree_cow != nullptr);
if (btree_cow == nullptr) {
return;
@@ -40,12 +39,12 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
BKE_nodetree_error_message_add(
- *btree_original, context, *node_.bnode(), type, std::move(message));
+ *btree_original, context, *node_->bnode(), type, std::move(message));
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
{
- for (const DSocket *socket : node_.inputs()) {
+ for (const InputSocketRef *socket : node_->inputs()) {
if (socket->is_available() && socket->name() == name) {
return socket->bsocket();
}
@@ -79,7 +78,7 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
* the domain is empty and we don't expect an attribute anyway). */
if (!name.empty() && component.attribute_domain_size(domain) != 0) {
this->error_message_add(NodeWarningType::Error,
- std::string("No attribute with name '") + name + "'.");
+ TIP_("No attribute with name \"") + name + "\"");
}
return component.attribute_get_constant_for_read(domain, type, default_value);
}
@@ -176,7 +175,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
const CPPType *requested_type) const
{
bNodeSocket *found_socket = nullptr;
- for (const DSocket *socket : node_.inputs()) {
+ for (const InputSocketRef *socket : node_->inputs()) {
if (socket->identifier() == identifier) {
found_socket = socket->bsocket();
break;
@@ -186,7 +185,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
if (found_socket == nullptr) {
std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
std::cout << "Possible identifiers are: ";
- for (const DSocket *socket : node_.inputs()) {
+ for (const InputSocketRef *socket : node_->inputs()) {
if (socket->is_available()) {
std::cout << "'" << socket->identifier() << "', ";
}
@@ -218,7 +217,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const
{
bNodeSocket *found_socket = nullptr;
- for (const DSocket *socket : node_.outputs()) {
+ for (const OutputSocketRef *socket : node_->outputs()) {
if (socket->identifier() == identifier) {
found_socket = socket->bsocket();
break;
@@ -228,7 +227,7 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va
if (found_socket == nullptr) {
std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
std::cout << "Possible identifiers are: ";
- for (const DSocket *socket : node_.outputs()) {
+ for (const OutputSocketRef *socket : node_->outputs()) {
if (socket->is_available()) {
std::cout << "'" << socket->identifier() << "', ";
}
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 60c2d6c37e1..2d60e959c44 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -712,6 +712,7 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_socket_type_float(PROP_FACTOR));
nodeRegisterSocketType(make_socket_type_float(PROP_ANGLE));
nodeRegisterSocketType(make_socket_type_float(PROP_TIME));
+ nodeRegisterSocketType(make_socket_type_float(PROP_DISTANCE));
nodeRegisterSocketType(make_socket_type_int(PROP_NONE));
nodeRegisterSocketType(make_socket_type_int(PROP_UNSIGNED));
diff --git a/source/blender/nodes/intern/node_tree_dependencies.cc b/source/blender/nodes/intern/node_tree_dependencies.cc
deleted file mode 100644
index 9d279dd4d75..00000000000
--- a/source/blender/nodes/intern/node_tree_dependencies.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "NOD_node_tree_dependencies.hh"
-
-#include "DNA_node_types.h"
-
-#include "BKE_node.h"
-
-namespace blender::nodes {
-
-static void add_dependencies_of_node_tree(bNodeTree &ntree, NodeTreeDependencies &r_dependencies)
-{
- /* TODO: Do a bit more sophisticated parsing to see which dependencies are really required. */
- LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->type == SOCK_OBJECT) {
- Object *object = reinterpret_cast<bNodeSocketValueObject *>(socket->default_value)->value;
- if (object != nullptr) {
- r_dependencies.add_transform_dependency(object);
- if (object->type == OB_MESH) {
- r_dependencies.add_geometry_dependency(object);
- }
- }
- }
- }
-
- if (node->type == NODE_GROUP) {
- bNodeTree *group = reinterpret_cast<bNodeTree *>(node->id);
- if (group != nullptr) {
- add_dependencies_of_node_tree(*group, r_dependencies);
- }
- }
- }
-}
-
-NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree)
-{
- NodeTreeDependencies dependencies;
- add_dependencies_of_node_tree(ntree, dependencies);
- return dependencies;
-}
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc
index c2391667e86..b973350becd 100644
--- a/source/blender/nodes/intern/node_tree_multi_function.cc
+++ b/source/blender/nodes/intern/node_tree_multi_function.cc
@@ -29,17 +29,17 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
Vector<fn::MFDataType, 10> input_types;
Vector<fn::MFDataType, 10> output_types;
- for (const DInputSocket *dsocket : dnode_.inputs()) {
+ for (const InputSocketRef *dsocket : dnode_->inputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
if (data_type.has_value()) {
input_types.append(*data_type);
}
}
}
- for (const DOutputSocket *dsocket : dnode_.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode_->outputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
if (data_type.has_value()) {
output_types.append(*data_type);
}
@@ -57,9 +57,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
Vector<fn::MFDataType, stack_capacity> input_types;
Vector<StringRef, stack_capacity> input_names;
- Vector<const DInputSocket *, stack_capacity> input_dsockets;
+ Vector<const InputSocketRef *, stack_capacity> input_dsockets;
- for (const DInputSocket *dsocket : dnode.inputs()) {
+ for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
@@ -72,9 +72,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
Vector<fn::MFDataType, stack_capacity> output_types;
Vector<StringRef, stack_capacity> output_names;
- Vector<const DOutputSocket *, stack_capacity> output_dsockets;
+ Vector<const OutputSocketRef *, stack_capacity> output_dsockets;
- for (const DOutputSocket *dsocket : dnode.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
@@ -86,20 +86,20 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
}
fn::MFDummyNode &dummy_node = common.network.add_dummy(
- dnode.name(), input_types, output_types, input_names, output_names);
+ dnode->name(), input_types, output_types, input_names, output_names);
- common.network_map.add(input_dsockets, dummy_node.inputs());
- common.network_map.add(output_dsockets, dummy_node.outputs());
+ common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs());
+ common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs());
}
static bool has_data_sockets(const DNode &dnode)
{
- for (const DInputSocket *socket : dnode.inputs()) {
+ for (const InputSocketRef *socket : dnode->inputs()) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
- for (const DOutputSocket *socket : dnode.outputs()) {
+ for (const OutputSocketRef *socket : dnode->outputs()) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
@@ -107,70 +107,39 @@ static bool has_data_sockets(const DNode &dnode)
return false;
}
+static void foreach_node_to_insert(CommonMFNetworkBuilderData &common,
+ FunctionRef<void(DNode)> callback)
+{
+ common.tree.foreach_node([&](const DNode dnode) {
+ if (dnode->is_group_node()) {
+ return;
+ }
+ /* Don't insert non-root group input/output nodes, because they will be inlined. */
+ if (!dnode.context()->is_root()) {
+ if (dnode->is_group_input_node() || dnode->is_group_output_node()) {
+ return;
+ }
+ }
+ callback(dnode);
+ });
+}
+
/**
* Expands all function nodes in the multi-function network. Nodes that don't have an expand
* function, but do have data sockets, will get corresponding dummy nodes.
*/
static void insert_nodes(CommonMFNetworkBuilderData &common)
{
- for (const DNode *dnode : common.tree.nodes()) {
- const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo;
+ foreach_node_to_insert(common, [&](const DNode dnode) {
+ const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network != nullptr) {
- NodeMFNetworkBuilder builder{common, *dnode};
+ NodeMFNetworkBuilder builder{common, dnode};
node_type->expand_in_mf_network(builder);
}
- else if (has_data_sockets(*dnode)) {
- insert_dummy_node(common, *dnode);
- }
- }
-}
-
-static void insert_group_inputs(CommonMFNetworkBuilderData &common)
-{
- for (const DGroupInput *group_input : common.tree.group_inputs()) {
- bNodeSocket *bsocket = group_input->bsocket();
- if (socket_is_mf_data_socket(*bsocket->typeinfo)) {
- bNodeSocketType *socktype = bsocket->typeinfo;
- BLI_assert(socktype->expand_in_mf_network != nullptr);
-
- SocketMFNetworkBuilder builder{common, *group_input};
- socktype->expand_in_mf_network(builder);
-
- fn::MFOutputSocket *from_socket = builder.built_socket();
- BLI_assert(from_socket != nullptr);
- common.network_map.add(*group_input, *from_socket);
+ else if (has_data_sockets(dnode)) {
+ insert_dummy_node(common, dnode);
}
- }
-}
-
-static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
- const DInputSocket &to_dsocket)
-{
- Span<const DOutputSocket *> from_dsockets = to_dsocket.linked_sockets();
- Span<const DGroupInput *> from_group_inputs = to_dsocket.linked_group_inputs();
- int total_linked_amount = from_dsockets.size() + from_group_inputs.size();
- BLI_assert(total_linked_amount <= 1);
-
- if (total_linked_amount == 0) {
- return nullptr;
- }
-
- if (from_dsockets.size() == 1) {
- const DOutputSocket &from_dsocket = *from_dsockets[0];
- if (!from_dsocket.is_available()) {
- return nullptr;
- }
- if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) {
- return &common.network_map.lookup(from_dsocket);
- }
- return nullptr;
- }
-
- const DGroupInput &from_group_input = *from_group_inputs[0];
- if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) {
- return &common.network_map.lookup(from_group_input);
- }
- return nullptr;
+ });
}
template<typename From, typename To>
@@ -202,20 +171,20 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float2, float3>(
conversions, "float2 to float3", [](float2 a) { return float3(a.x, a.y, 0.0f); });
add_implicit_conversion<float2, float>(
- conversions, "float2 to float", [](float2 a) { return a.length(); });
+ conversions, "float2 to float", [](float2 a) { return (a.x + a.y) / 2.0f; });
add_implicit_conversion<float2, int32_t>(
- conversions, "float2 to int32_t", [](float2 a) { return (int32_t)a.length(); });
+ conversions, "float2 to int32_t", [](float2 a) { return (int32_t)((a.x + a.y) / 2.0f); });
add_implicit_conversion<float2, bool>(
- conversions, "float2 to bool", [](float2 a) { return a.length_squared() == 0.0f; });
+ conversions, "float2 to bool", [](float2 a) { return !is_zero_v2(a); });
add_implicit_conversion<float2, Color4f>(
conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); });
add_implicit_conversion<float3, bool>(
- conversions, "float3 to boolean", [](float3 a) { return a.length_squared() == 0.0f; });
+ conversions, "float3 to boolean", [](float3 a) { return !is_zero_v3(a); });
add_implicit_conversion<float3, float>(
- conversions, "Vector Length", [](float3 a) { return a.length(); });
+ conversions, "float3 to float", [](float3 a) { return (a.x + a.y + a.z) / 3.0f; });
add_implicit_conversion<float3, int32_t>(
- conversions, "float3 to int32_t", [](float3 a) { return (int)a.length(); });
+ conversions, "float3 to int32_t", [](float3 a) { return (int)((a.x + a.y + a.z) / 3.0f); });
add_implicit_conversion<float3, float2>(conversions);
add_implicit_conversion<float3, Color4f>(
conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
@@ -226,6 +195,9 @@ static DataTypeConversions create_implicit_conversions()
conversions, "int32 to float2", [](int32_t a) { return float2((float)a); });
add_implicit_conversion<int32_t, float3>(
conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
+ add_implicit_conversion<int32_t, Color4f>(conversions, "int32 to Color4f", [](int32_t a) {
+ return Color4f((float)a, (float)a, (float)a, 1.0f);
+ });
add_implicit_conversion<bool, float>(conversions);
add_implicit_conversion<bool, int32_t>(conversions);
@@ -237,6 +209,9 @@ static DataTypeConversions create_implicit_conversions()
return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f);
});
+ add_implicit_conversion<Color4f, bool>(conversions, "Color4f to boolean", [](Color4f a) {
+ return a.r != 0.0f && a.g != 0.0f && a.b != 0.0f;
+ });
add_implicit_conversion<Color4f, float>(
conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
add_implicit_conversion<Color4f, float2>(
@@ -286,78 +261,82 @@ static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderD
return node.output(0);
}
-static void insert_links(CommonMFNetworkBuilderData &common)
+static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common,
+ const DInputSocket &dsocket)
{
- for (const DInputSocket *to_dsocket : common.tree.input_sockets()) {
- if (!to_dsocket->is_available()) {
- continue;
- }
- if (!to_dsocket->is_linked()) {
- continue;
- }
- if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) {
- continue;
- }
+ BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo()));
- Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket);
- BLI_assert(to_sockets.size() >= 1);
- fn::MFDataType to_type = to_sockets[0]->data_type();
-
- fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
- if (from_socket == nullptr) {
- from_socket = &insert_default_value_for_type(common, to_type);
- }
-
- fn::MFDataType from_type = from_socket->data_type();
-
- if (from_type != to_type) {
- const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
- from_type, to_type);
- if (conversion_fn != nullptr) {
- fn::MFNode &node = common.network.add_function(*conversion_fn);
- common.network.add_link(*from_socket, node.input(0));
- from_socket = &node.output(0);
- }
- else {
- from_socket = &insert_default_value_for_type(common, to_type);
- }
- }
+ SocketMFNetworkBuilder builder{common, dsocket};
+ socket_expand_in_mf_network(builder);
- for (fn::MFInputSocket *to_socket : to_sockets) {
- common.network.add_link(*from_socket, *to_socket);
- }
- }
+ fn::MFOutputSocket *built_socket = builder.built_socket();
+ BLI_assert(built_socket != nullptr);
+ return built_socket;
}
-static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket)
+static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common)
{
- bNodeSocket *bsocket = dsocket.bsocket();
- bNodeSocketType *socktype = bsocket->typeinfo;
- BLI_assert(socktype->expand_in_mf_network != nullptr);
-
- SocketMFNetworkBuilder builder{common, dsocket};
- socktype->expand_in_mf_network(builder);
-
- fn::MFOutputSocket *from_socket = builder.built_socket();
- BLI_assert(from_socket != nullptr);
+ foreach_node_to_insert(common, [&](const DNode dnode) {
+ for (const InputSocketRef *socket_ref : dnode->inputs()) {
+ const DInputSocket to_dsocket{dnode.context(), socket_ref};
+ if (!to_dsocket->is_available()) {
+ continue;
+ }
+ if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) {
+ continue;
+ }
- for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) {
- common.network.add_link(*from_socket, *to_socket);
- }
-}
+ Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(to_dsocket);
+ BLI_assert(to_sockets.size() >= 1);
+ const fn::MFDataType to_type = to_sockets[0]->data_type();
-static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
-{
- Vector<const DInputSocket *> unlinked_data_inputs;
- for (const DInputSocket *dsocket : common.tree.input_sockets()) {
- if (dsocket->is_available()) {
- if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
- if (!dsocket->is_linked()) {
- insert_unlinked_input(common, *dsocket);
+ Vector<DSocket> from_dsockets;
+ to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); });
+ if (from_dsockets.size() > 1) {
+ fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type);
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(from_socket, *to_socket);
+ }
+ continue;
+ }
+ if (from_dsockets.is_empty()) {
+ /* The socket is not linked. Need to use the value of the socket itself. */
+ fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket);
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*built_socket, *to_socket);
+ }
+ continue;
+ }
+ if (from_dsockets[0]->is_input()) {
+ DInputSocket from_dsocket{from_dsockets[0]};
+ fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket);
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*built_socket, *to_socket);
+ }
+ continue;
+ }
+ DOutputSocket from_dsocket{from_dsockets[0]};
+ fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket);
+ const fn::MFDataType from_type = from_socket->data_type();
+
+ if (from_type != to_type) {
+ const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
+ from_type, to_type);
+ if (conversion_fn != nullptr) {
+ fn::MFNode &node = common.network.add_function(*conversion_fn);
+ common.network.add_link(*from_socket, node.input(0));
+ from_socket = &node.output(0);
+ }
+ else {
+ from_socket = &insert_default_value_for_type(common, to_type);
}
}
+
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*from_socket, *to_socket);
+ }
}
- }
+ });
}
/**
@@ -376,9 +355,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
insert_nodes(common);
- insert_group_inputs(common);
- insert_links(common);
- insert_unlinked_inputs(common);
+ insert_links_and_unlinked_inputs(common);
return network_map;
}
@@ -420,16 +397,17 @@ static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map,
}
};
- for (const DInputSocket *dsocket : dnode.inputs()) {
+ for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
- for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
+ for (fn::MFInputSocket *mf_input :
+ network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
check_mf_node(mf_input->node());
}
}
}
- for (const DOutputSocket *dsocket : dnode.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
- fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
+ fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
check_mf_node(mf_output.node());
}
}
@@ -451,20 +429,21 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi
ResourceCollector &resources)
{
Vector<const fn::MFOutputSocket *> dummy_fn_inputs;
- for (const DInputSocket *dsocket : dnode.inputs()) {
+ for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo());
fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type);
- for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
+ for (fn::MFInputSocket *mf_input :
+ network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
network.add_link(fn_input, *mf_input);
dummy_fn_inputs.append(&fn_input);
}
}
}
Vector<const fn::MFInputSocket *> dummy_fn_outputs;
- for (const DOutputSocket *dsocket : dnode.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
- fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
+ fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
MFDataType data_type = mf_output.data_type();
fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type);
network.add_link(mf_output, fn_output);
@@ -492,18 +471,18 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
- for (const DNode *dnode : tree.nodes()) {
+ tree.foreach_node([&](DNode dnode) {
const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network == nullptr) {
/* This node does not have a multi-function implementation. */
- continue;
+ return;
}
- NodeMFNetworkBuilder builder{common, *dnode};
+ NodeMFNetworkBuilder builder{common, dnode};
node_type->expand_in_mf_network(builder);
const fn::MultiFunction *single_function = nullptr;
- const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function);
+ const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function);
switch (expand_type) {
case NodeExpandType::HasDummyNodes: {
@@ -519,12 +498,12 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
/* If a node expanded into multiple functions, a new function has to be created that
* combines those. */
const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple(
- *dnode, network, network_map, resources);
+ dnode, network, network_map, resources);
functions_by_node.add_new(dnode, &fn);
break;
}
}
- }
+ });
return functions_by_node;
}
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 9dcd90f9f50..4b326929dbb 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -25,7 +25,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
Map<bNode *, NodeRef *> node_mapping;
LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) {
- NodeRef &node = *allocator_.construct<NodeRef>();
+ NodeRef &node = *allocator_.construct<NodeRef>().release();
node.tree_ = this;
node.bnode_ = bnode;
@@ -33,7 +33,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
RNA_pointer_create(&btree->id, &RNA_Node, bnode, &node.rna_);
LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) {
- InputSocketRef &socket = *allocator_.construct<InputSocketRef>();
+ InputSocketRef &socket = *allocator_.construct<InputSocketRef>().release();
socket.node_ = &node;
socket.index_ = node.inputs_.append_and_get_index(&socket);
socket.is_input_ = true;
@@ -43,7 +43,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
}
LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) {
- OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>();
+ OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>().release();
socket.node_ = &node;
socket.index_ = node.outputs_.append_and_get_index(&socket);
socket.is_input_ = false;
@@ -52,6 +52,24 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
RNA_pointer_create(&btree->id, &RNA_NodeSocket, bsocket, &socket.rna_);
}
+ LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) {
+ InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>().release();
+ internal_link.blink_ = blink;
+ for (InputSocketRef *socket_ref : node.inputs_) {
+ if (socket_ref->bsocket_ == blink->fromsock) {
+ internal_link.from_ = socket_ref;
+ break;
+ }
+ }
+ for (OutputSocketRef *socket_ref : node.outputs_) {
+ if (socket_ref->bsocket_ == blink->tosock) {
+ internal_link.to_ = socket_ref;
+ break;
+ }
+ }
+ node.internal_links_.append(&internal_link);
+ }
+
input_sockets_.extend(node.inputs_.as_span());
output_sockets_.extend(node.outputs_.as_span());
@@ -64,19 +82,31 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
InputSocketRef &to_socket = this->find_input_socket(
node_mapping, blink->tonode, blink->tosock);
- from_socket.directly_linked_sockets_.append(&to_socket);
- to_socket.directly_linked_sockets_.append(&from_socket);
+ LinkRef &link = *allocator_.construct<LinkRef>().release();
+ link.from_ = &from_socket;
+ link.to_ = &to_socket;
+ link.blink_ = blink;
+
+ links_.append(&link);
+
+ from_socket.directly_linked_links_.append(&link);
+ to_socket.directly_linked_links_.append(&link);
}
- for (OutputSocketRef *socket : output_sockets_) {
- if (!socket->node_->is_reroute_node()) {
- this->find_targets_skipping_reroutes(*socket, socket->linked_sockets_);
- for (SocketRef *target : socket->linked_sockets_) {
- target->linked_sockets_.append(socket);
- }
+ for (InputSocketRef *input_socket : input_sockets_) {
+ if (input_socket->is_multi_input_socket()) {
+ std::sort(input_socket->directly_linked_links_.begin(),
+ input_socket->directly_linked_links_.end(),
+ [&](const LinkRef *a, const LinkRef *b) -> bool {
+ int index_a = a->blink()->multi_input_socket_index;
+ int index_b = b->blink()->multi_input_socket_index;
+ return index_a > index_b;
+ });
}
}
+ this->create_linked_socket_caches();
+
for (NodeRef *node : nodes_by_id_) {
const bNodeType *nodetype = node->bnode_->typeinfo;
nodes_by_type_.add(nodetype, node);
@@ -85,6 +115,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
NodeTreeRef::~NodeTreeRef()
{
+ /* The destructor has to be called manually, because these types are allocated in a linear
+ * allocator. */
for (NodeRef *node : nodes_by_id_) {
node->~NodeRef();
}
@@ -94,6 +126,9 @@ NodeTreeRef::~NodeTreeRef()
for (OutputSocketRef *socket : output_sockets_) {
socket->~OutputSocketRef();
}
+ for (LinkRef *link : links_) {
+ link->~LinkRef();
+ }
}
InputSocketRef &NodeTreeRef::find_input_socket(Map<bNode *, NodeRef *> &node_mapping,
@@ -124,15 +159,84 @@ OutputSocketRef &NodeTreeRef::find_output_socket(Map<bNode *, NodeRef *> &node_m
return *node->outputs_[0];
}
-void NodeTreeRef::find_targets_skipping_reroutes(OutputSocketRef &socket,
- Vector<SocketRef *> &r_targets)
+void NodeTreeRef::create_linked_socket_caches()
+{
+ for (InputSocketRef *socket : input_sockets_) {
+ /* Find directly linked socket based on incident links. */
+ Vector<SocketRef *> directly_linked_sockets;
+ for (LinkRef *link : socket->directly_linked_links_) {
+ directly_linked_sockets.append(link->from_);
+ }
+ socket->directly_linked_sockets_ = allocator_.construct_array_copy(
+ directly_linked_sockets.as_span());
+
+ /* Find linked sockets when skipping reroutes. */
+ Vector<SocketRef *> linked_sockets;
+ this->foreach_origin_skipping_reroutes_and_muted_links(
+ *socket, [&](OutputSocketRef &origin) { linked_sockets.append(&origin); });
+ if (linked_sockets == directly_linked_sockets) {
+ socket->linked_sockets_without_reroutes_and_muted_links_ = socket->directly_linked_sockets_;
+ }
+ else {
+ socket->linked_sockets_without_reroutes_and_muted_links_ = allocator_.construct_array_copy(
+ linked_sockets.as_span());
+ }
+ }
+
+ for (OutputSocketRef *socket : output_sockets_) {
+ /* Find directly linked socket based on incident links. */
+ Vector<SocketRef *> directly_linked_sockets;
+ for (LinkRef *link : socket->directly_linked_links_) {
+ directly_linked_sockets.append(link->to_);
+ }
+ socket->directly_linked_sockets_ = allocator_.construct_array_copy(
+ directly_linked_sockets.as_span());
+
+ /* Find linked sockets when skipping reroutes. */
+ Vector<SocketRef *> linked_sockets;
+ this->foreach_target_skipping_reroutes_and_muted_links(
+ *socket, [&](InputSocketRef &target) { linked_sockets.append(&target); });
+ if (linked_sockets == directly_linked_sockets) {
+ socket->linked_sockets_without_reroutes_and_muted_links_ = socket->directly_linked_sockets_;
+ }
+ else {
+ socket->linked_sockets_without_reroutes_and_muted_links_ = allocator_.construct_array_copy(
+ linked_sockets.as_span());
+ }
+ }
+}
+
+void NodeTreeRef::foreach_origin_skipping_reroutes_and_muted_links(
+ InputSocketRef &socket, FunctionRef<void(OutputSocketRef &)> callback)
{
- for (SocketRef *direct_target : socket.directly_linked_sockets_) {
- if (direct_target->node_->is_reroute_node()) {
- this->find_targets_skipping_reroutes(*direct_target->node_->outputs_[0], r_targets);
+ for (LinkRef *link : socket.directly_linked_links_) {
+ if (link->is_muted()) {
+ continue;
+ }
+ OutputSocketRef *origin = link->from_;
+ if (origin->node_->is_reroute_node()) {
+ this->foreach_origin_skipping_reroutes_and_muted_links(*origin->node_->inputs_[0], callback);
}
else {
- r_targets.append_non_duplicates(direct_target);
+ callback(*(OutputSocketRef *)origin);
+ }
+ }
+}
+
+void NodeTreeRef::foreach_target_skipping_reroutes_and_muted_links(
+ OutputSocketRef &socket, FunctionRef<void(InputSocketRef &)> callback)
+{
+ for (LinkRef *link : socket.directly_linked_links_) {
+ if (link->is_muted()) {
+ continue;
+ }
+ InputSocketRef *target = link->to_;
+ if (target->node_->is_reroute_node()) {
+ this->foreach_target_skipping_reroutes_and_muted_links(*target->node_->outputs_[0],
+ callback);
+ }
+ else {
+ callback(*(InputSocketRef *)target);
}
}
}
@@ -216,4 +320,10 @@ std::string NodeTreeRef::to_dot() const
return digraph.to_dot_string();
}
+const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree)
+{
+ return *node_tree_refs.lookup_or_add_cb(&btree,
+ [&]() { return std::make_unique<NodeTreeRef>(&btree); });
+}
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index a385cb7039f..3fb4d10979d 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -388,7 +388,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
if (is_group || is_group_output) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->link != NULL) {
+ if (socket->link != NULL && !(socket->link->flag & NODE_LINK_MUTED)) {
bNodeLink *link = socket->link;
/* Fix the case where the socket is actually converting the data. (see T71374)
* We only do the case of lossy conversion to float.*/
@@ -557,7 +557,7 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
/* Non-cycles node is used as an output. */
return false;
}
- if (displacement->link != NULL) {
+ if ((displacement->link != NULL) && !(displacement->link->flag & NODE_LINK_MUTED)) {
*r_node = displacement->link->fromnode;
*r_socket = displacement->link->fromsock;
*r_link = displacement->link;
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 25d6aef69e5..1a2405e021f 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -257,11 +257,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
}
if (do_it) {
- if (node->typeinfo->gpufunc) {
+ if (node->typeinfo->gpu_fn) {
node_get_stack(node, stack, nsin, nsout);
gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
- if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout)) {
+ if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) {
data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
index 36971d4e799..abe80ebcefb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
@@ -47,8 +47,15 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
float inverted = node->custom2 ? 1.0f : 0.0f;
+ float f_samples = divide_ceil_u(node->custom1, 4);
- return GPU_stack_link(mat, node, "node_ambient_occlusion", in, out, GPU_constant(&inverted));
+ return GPU_stack_link(mat,
+ node,
+ "node_ambient_occlusion",
+ in,
+ out,
+ GPU_constant(&inverted),
+ GPU_constant(&f_samples));
}
static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node)
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index cc1968cb1b1..d8f560277f2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -46,7 +46,7 @@ void register_node_type_sh_brightcontrast(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 747979522d1..b48838e5f56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -62,7 +62,7 @@ void register_node_type_sh_gamma(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 57ef51c65f6..7a05fc95eec 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -89,7 +89,7 @@ void register_node_type_sh_hue_sat(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
index 19fa0b0309d..0d6709a1968 100644
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.c
@@ -69,7 +69,7 @@ void register_node_type_sh_invert(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
node_type_gpu(&ntype, gpu_shader_invert);
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index f54914ceba9..7a846031456 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -116,7 +116,7 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild
blender::fn::MFNetwork &network = builder.network();
blender::fn::MFFunctionNode &base_node = network.add_function(base_function);
- builder.network_map().add_try_match(dnode.inputs(), base_node.inputs());
+ builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs());
const bool clamp_output = builder.bnode().custom2 != 0;
if (clamp_output) {
@@ -126,10 +126,12 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild
}};
blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn);
network.add_link(base_node.output(0), clamp_node.input(0));
- builder.network_map().add(dnode.output(0), clamp_node.output(0));
+ builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
+ clamp_node.output(0));
}
else {
- builder.network_map().add(dnode.output(0), base_node.output(0));
+ builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
+ base_node.output(0));
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 8725122b12c..090c6216224 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -106,7 +106,7 @@ void register_node_type_sh_mix_rgb(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_mix_rgb_in, sh_node_mix_rgb_out);
node_type_label(&ntype, node_blend_label);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_mix_rgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
index 2c9b77530a2..951755be4f3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
@@ -61,7 +61,7 @@ void register_node_type_sh_sephsv(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
node_type_gpu(&ntype, gpu_shader_sephsv);
@@ -109,7 +109,7 @@ void register_node_type_sh_combhsv(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
node_type_gpu(&ntype, gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 41c978e75ba..26a1db1f3a6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -90,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
sampler &= ~GPU_SAMPLER_REPEAT;
}
- const char *gpufunc;
+ const char *gpu_fn;
static const char *names[] = {
"node_tex_image_linear",
"node_tex_image_cubic",
@@ -98,19 +98,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
switch (tex->interpolation) {
case SHD_INTERP_LINEAR:
- gpufunc = names[0];
+ gpu_fn = names[0];
break;
case SHD_INTERP_CLOSEST:
sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP);
- gpufunc = names[0];
+ gpu_fn = names[0];
break;
default:
- gpufunc = names[1];
+ gpu_fn = names[1];
break;
}
/* Sample texture with correct interpolation. */
- GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha);
+ GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha);
if (out[0].hasoutput) {
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 67268c102c5..7b67c2d1f2e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -91,7 +91,7 @@ void register_node_type_sh_tex_noise(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
+ sh_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
node_type_socket_templates(&ntype, sh_node_tex_noise_in, sh_node_tex_noise_out);
node_type_init(&ntype, node_shader_init_tex_noise);
node_type_storage(
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
index 56ecb6d4476..60a3392c761 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
@@ -71,8 +71,7 @@ void register_node_type_sh_tex_white_noise(void)
{
static bNodeType ntype;
- sh_fn_node_type_base(
- &ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
+ sh_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
node_type_socket_templates(&ntype, sh_node_tex_white_noise_in, sh_node_tex_white_noise_out);
node_type_init(&ntype, node_shader_init_tex_white_noise);
node_type_gpu(&ntype, gpu_shader_tex_white_noise);
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index 5a8a1b847cc..495c8d12824 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -41,7 +41,7 @@ static int gpu_shader_value(GPUMaterial *mat,
static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
{
- const bNodeSocket *bsocket = builder.dnode().output(0).bsocket();
+ const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket();
const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value;
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c
deleted file mode 100644
index b2132c59cde..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c
+++ /dev/null
@@ -1,80 +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) 2013 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "../node_shader_util.h"
-
-/* **************** Vector Rotate ******************** */
-static bNodeSocketTemplate sh_node_vector_rotate_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
- {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE},
- {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE},
- {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_vector_rotate_out[] = {{SOCK_VECTOR, N_("Vector")}, {-1, ""}};
-
-static int gpu_shader_vector_rotate(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
-
- static const char *names[] = {
- [NODE_VECTOR_ROTATE_TYPE_AXIS] = "node_vector_rotate_axis_angle",
- [NODE_VECTOR_ROTATE_TYPE_AXIS_X] = "node_vector_rotate_axis_x",
- [NODE_VECTOR_ROTATE_TYPE_AXIS_Y] = "node_vector_rotate_axis_y",
- [NODE_VECTOR_ROTATE_TYPE_AXIS_Z] = "node_vector_rotate_axis_z",
- [NODE_VECTOR_ROTATE_TYPE_EULER_XYZ] = "node_vector_rotate_euler_xyz",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- float invert = (node->custom2) ? -1.0 : 1.0;
- return GPU_stack_link(mat, node, names[node->custom1], in, out, GPU_constant(&invert));
- }
-
- return 0;
-}
-
-static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node)
-{
- bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation");
- nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
- bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis");
- nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS));
- bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle");
- nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
-}
-
-void register_node_type_sh_vector_rotate(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out);
- node_type_gpu(&ntype, gpu_shader_vector_rotate);
- node_type_update(&ntype, node_shader_update_vector_rotate);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
new file mode 100644
index 00000000000..30b043439b8
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -0,0 +1,217 @@
+/*
+ * 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) 2013 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** Vector Rotate ******************** */
+static bNodeSocketTemplate sh_node_vector_rotate_in[] = {
+ {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
+ {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE},
+ {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""}};
+
+static bNodeSocketTemplate sh_node_vector_rotate_out[] = {
+ {SOCK_VECTOR, N_("Vector")},
+ {-1, ""},
+};
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_VECTOR_ROTATE_TYPE_AXIS:
+ return "node_vector_rotate_axis_angle";
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
+ return "node_vector_rotate_axis_x";
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
+ return "node_vector_rotate_axis_y";
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
+ return "node_vector_rotate_axis_z";
+ case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ:
+ return "node_vector_rotate_euler_xyz";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_vector_rotate(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const char *name = gpu_shader_get_name(node->custom1);
+
+ if (name != nullptr) {
+ float invert = (node->custom2) ? -1.0 : 1.0;
+ return GPU_stack_link(mat, node, name, in, out, GPU_constant(&invert));
+ }
+
+ return 0;
+}
+
+using blender::float3;
+
+static float3 sh_node_vector_rotate_around_axis(const float3 vector,
+ const float3 center,
+ const float3 axis,
+ const float angle)
+{
+ float3 result = vector - center;
+ float mat[3][3];
+ axis_angle_to_mat3(mat, axis, angle);
+ mul_m3_v3(mat, result);
+ return result + center;
+}
+
+static float3 sh_node_vector_rotate_euler(const float3 vector,
+ const float3 center,
+ const float3 rotation,
+ const bool invert)
+{
+ float mat[3][3];
+ float3 result = vector - center;
+ eul_to_mat3(mat, rotation);
+ if (invert) {
+ invert_m3(mat);
+ }
+ mul_m3_v3(mat, result);
+ return result + center;
+}
+
+static const blender::fn::MultiFunction &get_multi_function(
+ blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ bool invert = builder.bnode().custom2;
+ const int mode = builder.bnode().custom1;
+
+ switch (mode) {
+ case NODE_VECTOR_ROTATE_TYPE_AXIS: {
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
+ "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
+ "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_X: {
+ float3 axis = float3(1.0f, 0.0f, 0.0f);
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate X-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate X-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: {
+ float3 axis = float3(0.0f, 1.0f, 0.0f);
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: {
+ float3 axis = float3(0.0f, 0.0f, 1.0f);
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ "Rotate Euler", [](float3 in, float3 center, float3 rotation) {
+ return sh_node_vector_rotate_euler(in, center, rotation, true);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ "Rotate Euler", [](float3 in, float3 center, float3 rotation) {
+ return sh_node_vector_rotate_euler(in, center, rotation, false);
+ }};
+ return fn;
+ }
+ default:
+ BLI_assert(false);
+ return builder.get_not_implemented_fn();
+ }
+}
+
+static void sh_node_vector_rotate_expand_in_mf_network(
+ blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ const blender::fn::MultiFunction &fn = get_multi_function(builder);
+ builder.set_matching_fn(fn);
+}
+
+static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation");
+ nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
+ bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis");
+ nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS));
+ bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle");
+ nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
+}
+
+void register_node_type_sh_vector_rotate(void)
+{
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out);
+ node_type_gpu(&ntype, gpu_shader_vector_rotate);
+ node_type_update(&ntype, node_shader_update_vector_rotate);
+ ntype.expand_in_mf_network = sh_node_vector_rotate_expand_in_mf_network;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
index ef795268158..5214d156adf 100644
--- a/source/blender/python/gpu/gpu_py_batch.c
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -279,8 +279,8 @@ static void pygpu_batch__tp_dealloc(BPyGPUBatch *self)
GPU_batch_discard(self->batch);
#ifdef USE_GPU_PY_REFERENCES
+ PyObject_GC_UnTrack(self);
if (self->references) {
- PyObject_GC_UnTrack(self);
pygpu_batch__tp_clear(self);
Py_XDECREF(self->references);
}
@@ -295,18 +295,10 @@ PyDoc_STRVAR(
"\n"
" Reusable container for drawable geometry.\n"
"\n"
- " :arg type: One of these primitive types: {\n"
- " `POINTS`,\n"
- " `LINES`,\n"
- " `TRIS`,\n"
- " `LINE_STRIP`,\n"
- " `LINE_LOOP`,\n"
- " `TRI_STRIP`,\n"
- " `TRI_FAN`,\n"
- " `LINES_ADJ`,\n"
- " `TRIS_ADJ`,\n"
- " `LINE_STRIP_ADJ` }\n"
- " :type type: `str`\n"
+ " :arg type: The primitive type of geometry to be drawn.\n"
+ " Possible values are `POINTS`, `LINES`, `TRIS`, `LINE_STRIP`, `LINE_LOOP`, `TRI_STRIP`, "
+ "`TRI_FAN`, `LINES_ADJ`, `TRIS_ADJ` and `LINE_STRIP_ADJ`.\n"
+ " :type type: str\n"
" :arg buf: Vertex buffer containing all or some of the attributes required for drawing.\n"
" :type buf: :class:`gpu.types.GPUVertBuf`\n"
" :arg elem: An optional index buffer.\n"
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index b89d2c6a69f..d0965e83e33 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -202,8 +202,7 @@ static void pygpu_buffer__tp_dealloc(BPyGPUBuffer *self)
{
if (self->parent) {
PyObject_GC_UnTrack(self);
- pygpu_buffer__tp_clear(self);
- Py_XDECREF(self->parent);
+ Py_CLEAR(self->parent);
}
else {
MEM_freeN(self->buf.as_void);
@@ -590,23 +589,19 @@ static PyBufferProcs pygpu_buffer__tp_as_buffer = {
};
#endif
-PyDoc_STRVAR(pygpu_buffer__tp_doc,
- ".. class:: Buffer(format, dimensions, data)\n"
- "\n"
- " For Python access to GPU functions requiring a pointer.\n"
- "\n"
- " :arg format: One of these primitive types: {\n"
- " `FLOAT`,\n"
- " `INT`,\n"
- " `UINT`,\n"
- " `UBYTE`,\n"
- " `UINT_24_8`,\n"
- " `10_11_11_REV`,\n"
- " :type type: `str`\n"
- " :arg dimensions: Array describing the dimensions.\n"
- " :type dimensions: `int`\n"
- " :arg data: Optional data array.\n"
- " :type data: `array`\n");
+PyDoc_STRVAR(
+ pygpu_buffer__tp_doc,
+ ".. class:: Buffer(format, dimensions, data)\n"
+ "\n"
+ " For Python access to GPU functions requiring a pointer.\n"
+ "\n"
+ " :arg format: Format type to interpret the buffer.\n"
+ " Possible values are `FLOAT`, `INT`, `UINT`, `UBYTE`, `UINT_24_8` and `10_11_11_REV`.\n"
+ " :type type: str\n"
+ " :arg dimensions: Array describing the dimensions.\n"
+ " :type dimensions: int\n"
+ " :arg data: Optional data array.\n"
+ " :type data: sequence\n");
PyTypeObject BPyGPU_BufferType = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "Buffer",
.tp_basicsize = sizeof(BPyGPUBuffer),
diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c
index 2beabe6a93d..0cb5e9a2785 100644
--- a/source/blender/python/gpu/gpu_py_element.c
+++ b/source/blender/python/gpu/gpu_py_element.c
@@ -184,12 +184,9 @@ PyDoc_STRVAR(pygpu_IndexBuf__tp_doc,
"\n"
" Contains an index buffer.\n"
"\n"
- " :param type: One of these primitive types: {\n"
- " `POINTS`,\n"
- " `LINES`,\n"
- " `TRIS`,\n"
- " `LINE_STRIP_ADJ` }\n"
- " :type type: `str`\n"
+ " :arg type: The primitive type this index buffer is composed of.\n"
+ " Possible values are `POINTS`, `LINES`, `TRIS` and `LINE_STRIP_ADJ`.\n"
+ " :type type: str\n"
" :param seq: Indices this index buffer will contain.\n"
" Whether a 1D or 2D sequence is required depends on the type.\n"
" Optionally the sequence can support the buffer protocol.\n"
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c
index 5bf577f3b96..34d17bb10c3 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.c
+++ b/source/blender/python/gpu/gpu_py_framebuffer.c
@@ -356,9 +356,9 @@ PyDoc_STRVAR(pygpu_framebuffer_clear_doc,
" :arg color: float sequence each representing ``(r, g, b, a)``.\n"
" :type color: sequence of 3 or 4 floats\n"
" :arg depth: depth value.\n"
- " :type depth: `float`\n"
+ " :type depth: float\n"
" :arg stencil: stencil value.\n"
- " :type stencil: `int`\n");
+ " :type stencil: int\n");
static PyObject *pygpu_framebuffer_clear(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
{
PYGPU_FRAMEBUFFER_CHECK_OBJ(self);
@@ -417,7 +417,7 @@ PyDoc_STRVAR(pygpu_framebuffer_viewport_set_doc,
"\n"
" :param x, y: lower left corner of the viewport_set rectangle, in pixels.\n"
" :param xsize, ysize: width and height of the viewport_set.\n"
- " :type x, y, xsize, ysize: `int`\n");
+ " :type x, y, xsize, ysize: int\n");
static PyObject *pygpu_framebuffer_viewport_set(BPyGPUFrameBuffer *self,
PyObject *args,
void *UNUSED(type))
@@ -510,10 +510,10 @@ PyDoc_STRVAR(pygpu_framebuffer__tp_doc,
"\n"
" :arg depth_slot: GPUTexture to attach or a `dict` containing keywords: "
"'texture', 'layer' and 'mip'.\n"
- " :type depth_slot: :class:`gpu.types.GPUTexture`, `dict` or `Nonetype`\n"
+ " :type depth_slot: :class:`gpu.types.GPUTexture`, dict or Nonetype\n"
" :arg color_slots: Tuple where each item can be a GPUTexture or a `dict` "
"containing keywords: 'texture', 'layer' and 'mip'.\n"
- " :type color_slots: `tuple` or `Nonetype`\n");
+ " :type color_slots: tuple or Nonetype\n");
PyTypeObject BPyGPUFrameBuffer_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUFrameBuffer",
.tp_basicsize = sizeof(BPyGPUFrameBuffer),
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 9d5671ff702..9e9a0b9066a 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -96,20 +96,20 @@ static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs)
typedef struct {
PyObject_HEAD /* required python macro */
- BPyGPUOffScreen *py_offs;
+ BPyGPUOffScreen *py_offscreen;
int level;
bool is_explicitly_bound; /* Bound by "bind" method. */
} OffScreenStackContext;
static void pygpu_offscreen_stack_context__tp_dealloc(OffScreenStackContext *self)
{
- Py_DECREF(self->py_offs);
+ Py_DECREF(self->py_offscreen);
PyObject_DEL(self);
}
static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self)
{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs);
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen);
if (!self->is_explicitly_bound) {
if (self->level != -1) {
@@ -117,7 +117,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self
return NULL;
}
- GPU_offscreen_bind(self->py_offs->ofs, true);
+ GPU_offscreen_bind(self->py_offscreen->ofs, true);
self->level = GPU_framebuffer_stack_level_get();
}
@@ -127,7 +127,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self
static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self,
PyObject *UNUSED(args))
{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs);
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen);
if (self->level == -1) {
PyErr_SetString(PyExc_RuntimeError, "Not yet in use\n");
@@ -140,7 +140,7 @@ static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self,
PyExc_RuntimeError, "Level of bind mismatch, expected %d, got %d\n", self->level, level);
}
- GPU_offscreen_unbind(self->py_offs->ofs, true);
+ GPU_offscreen_unbind(self->py_offscreen->ofs, true);
Py_RETURN_NONE;
}
@@ -166,7 +166,7 @@ static PyObject *pygpu_offscreen_bind(BPyGPUOffScreen *self)
{
OffScreenStackContext *ret = PyObject_New(OffScreenStackContext,
&PyGPUOffscreenStackContext_Type);
- ret->py_offs = self;
+ ret->py_offscreen = self;
ret->level = -1;
ret->is_explicitly_bound = false;
Py_INCREF(self);
@@ -184,7 +184,7 @@ PyDoc_STRVAR(pygpu_offscreen_unbind_doc,
"\n"
" :arg restore: Restore the OpenGL state, can only be used when the state has been "
"saved before.\n"
- " :type restore: `bool`\n");
+ " :type restore: bool\n");
static PyObject *pygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
{
bool restore = true;
@@ -336,8 +336,8 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
region,
GPU_offscreen_width(self->ofs),
GPU_offscreen_height(self->ofs),
- (float(*)[4])py_mat_view->matrix,
- (float(*)[4])py_mat_projection->matrix,
+ (const float(*)[4])py_mat_view->matrix,
+ (const float(*)[4])py_mat_projection->matrix,
true,
true,
"",
@@ -412,9 +412,9 @@ PyDoc_STRVAR(pygpu_offscreen__tp_doc,
" This object gives access to off screen buffers.\n"
"\n"
" :arg width: Horizontal dimension of the buffer.\n"
- " :type width: `int`\n"
+ " :type width: int\n"
" :arg height: Vertical dimension of the buffer.\n"
- " :type height: `int`\n");
+ " :type height: int\n");
PyTypeObject BPyGPUOffScreen_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUOffScreen",
.tp_basicsize = sizeof(BPyGPUOffScreen),
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 4237e2d4b2d..fc3a7d1360b 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -130,9 +130,9 @@ PyDoc_STRVAR(pygpu_shader_uniform_from_name_doc,
" Get uniform location by name.\n"
"\n"
" :param name: Name of the uniform variable whose location is to be queried.\n"
- " :type name: `str`\n"
+ " :type name: str\n"
" :return: Location of the uniform variable.\n"
- " :rtype: `int`\n");
+ " :rtype: int\n");
static PyObject *pygpu_shader_uniform_from_name(BPyGPUShader *self, PyObject *arg)
{
const char *name = PyUnicode_AsUTF8(arg);
@@ -157,9 +157,9 @@ PyDoc_STRVAR(
" Get uniform block location by name.\n"
"\n"
" :param name: Name of the uniform block variable whose location is to be queried.\n"
- " :type name: `str`\n"
+ " :type name: str\n"
" :return: The location of the uniform block variable.\n"
- " :rtype: `int`\n");
+ " :rtype: int\n");
static PyObject *pygpu_shader_uniform_block_from_name(BPyGPUShader *self, PyObject *arg)
{
const char *name = PyUnicode_AsUTF8(arg);
@@ -559,7 +559,7 @@ PyDoc_STRVAR(pygpu_shader_calc_format_doc,
" Build a new format based on the attributes of the shader.\n"
"\n"
" :return: vertex attribute format for the shader\n"
- " :rtype: GPUVertFormat\n");
+ " :rtype: :class:`gpu.types.GPUVertFormat`\n");
static PyObject *pygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg))
{
BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c
index d1b3a01e2e4..110f5a6ff55 100644
--- a/source/blender/python/gpu/gpu_py_state.c
+++ b/source/blender/python/gpu/gpu_py_state.c
@@ -78,24 +78,27 @@ static const struct PyC_StringEnumItems pygpu_state_faceculling_items[] = {
/** \name Manage Stack
* \{ */
-PyDoc_STRVAR(pygpu_state_blend_set_doc,
- ".. function:: blend_set(mode)\n"
- "\n"
- " Defines the fixed pipeline blending equation.\n"
- "\n"
- " :param mode: One of these modes: {\n"
- " `NONE`,\n"
- " `ALPHA`,\n"
- " `ALPHA_PREMULT`,\n"
- " `ADDITIVE`,\n"
- " `ADDITIVE_PREMULT`,\n"
- " `MULTIPLY`,\n"
- " `SUBTRACT`,\n"
- " `INVERT`,\n"
- //" `OIT`,\n"
- //" `BACKGROUND`,\n"
- //" `CUSTOM`,\n"
- " :type mode: `str`\n");
+PyDoc_STRVAR(
+ pygpu_state_blend_set_doc,
+ ".. function:: blend_set(mode)\n"
+ "\n"
+ " Defines the fixed pipeline blending equation.\n"
+ "\n"
+ " :param mode: The type of blend mode.\n"
+ " * ``NONE`` No blending.\n"
+ " * ``ALPHA`` The original color channels are interpolated according to the alpha value.\n"
+ " * ``ALPHA_PREMULT`` The original color channels are interpolated according to the alpha "
+ "value with the new colors pre-multiplied by this value.\n"
+ " * ``ADDITIVE`` The original color channels are added by the corresponding ones.\n"
+ " * ``ADDITIVE_PREMULT`` The original color channels are added by the corresponding ones "
+ "that are pre-multiplied by the alpha value.\n"
+ " * ``MULTIPLY`` The original color channels are multiplied by the corresponding ones.\n"
+ " * ``SUBTRACT`` The original color channels are subtracted by the corresponding ones.\n"
+ " * ``INVERT`` The original color channels are replaced by its complementary color.\n"
+ //" * ``OIT``.\n"
+ //" * ``BACKGROUND`` .\n"
+ //" * ``CUSTOM`` .\n"
+ " :type mode: str\n");
static PyObject *pygpu_state_blend_set(PyObject *UNUSED(self), PyObject *value)
{
struct PyC_StringEnum pygpu_blend = {pygpu_state_blend_items};
@@ -122,15 +125,10 @@ PyDoc_STRVAR(pygpu_state_depth_test_set_doc,
"\n"
" Defines the depth_test equation.\n"
"\n"
- " :param mode: One of these modes: {\n"
- " `NONE`,\n"
- " `ALWAYS`,\n"
- " `LESS`,\n"
- " `LESS_EQUAL`,\n"
- " `EQUAL`,\n"
- " `GREATER`,\n"
- " `GREATER_EQUAL`,\n"
- " :type mode: `str`\n");
+ " :param mode: The depth test equation name.\n"
+ " Possible values are `NONE`, `ALWAYS`, `LESS`, `LESS_EQUAL`, `EQUAL`, "
+ "`GREATER` and `GREATER_EQUAL`.\n"
+ " :type mode: str\n");
static PyObject *pygpu_state_depth_test_set(PyObject *UNUSED(self), PyObject *value)
{
struct PyC_StringEnum pygpu_depth_test = {pygpu_state_depthtest_items};
@@ -158,7 +156,7 @@ PyDoc_STRVAR(pygpu_state_depth_mask_set_doc,
" Write to depth component.\n"
"\n"
" :param value: True for writing to the depth component.\n"
- " :type near: `bool`\n");
+ " :type near: bool\n");
static PyObject *pygpu_state_depth_mask_set(PyObject *UNUSED(self), PyObject *value)
{
bool write_to_depth;
@@ -186,7 +184,7 @@ PyDoc_STRVAR(pygpu_state_viewport_set_doc,
"\n"
" :param x, y: lower left corner of the viewport_set rectangle, in pixels.\n"
" :param width, height: width and height of the viewport_set.\n"
- " :type x, y, xsize, ysize: `int`\n");
+ " :type x, y, xsize, ysize: int\n");
static PyObject *pygpu_state_viewport_set(PyObject *UNUSED(self), PyObject *args)
{
int x, y, xsize, ysize;
@@ -222,7 +220,7 @@ PyDoc_STRVAR(pygpu_state_line_width_set_doc,
" Specify the width of rasterized lines.\n"
"\n"
" :param size: New width.\n"
- " :type mode: `float`\n");
+ " :type mode: float\n");
static PyObject *pygpu_state_line_width_set(PyObject *UNUSED(self), PyObject *value)
{
float width = (float)PyFloat_AsDouble(value);
@@ -250,7 +248,7 @@ PyDoc_STRVAR(pygpu_state_point_size_set_doc,
" Specify the diameter of rasterized points.\n"
"\n"
" :param size: New diameter.\n"
- " :type mode: `float`\n");
+ " :type mode: float\n");
static PyObject *pygpu_state_point_size_set(PyObject *UNUSED(self), PyObject *value)
{
float size = (float)PyFloat_AsDouble(value);
@@ -268,7 +266,7 @@ PyDoc_STRVAR(pygpu_state_color_mask_set_doc,
" Enable or disable writing of frame buffer color components.\n"
"\n"
" :param r, g, b, a: components red, green, blue, and alpha.\n"
- " :type r, g, b, a: `bool`\n");
+ " :type r, g, b, a: bool\n");
static PyObject *pygpu_state_color_mask_set(PyObject *UNUSED(self), PyObject *args)
{
int r, g, b, a;
@@ -285,11 +283,8 @@ PyDoc_STRVAR(pygpu_state_face_culling_set_doc,
"\n"
" Specify whether none, front-facing or back-facing facets can be culled.\n"
"\n"
- " :param mode: One of these modes: {\n"
- " `NONE`,\n"
- " `FRONT`,\n"
- " `BACK`,\n"
- " :type mode: `str`\n");
+ " :param mode: `NONE`, `FRONT` or `BACK`.\n"
+ " :type mode: str\n");
static PyObject *pygpu_state_face_culling_set(PyObject *UNUSED(self), PyObject *value)
{
struct PyC_StringEnum pygpu_faceculling = {pygpu_state_faceculling_items};
@@ -307,7 +302,7 @@ PyDoc_STRVAR(pygpu_state_front_facing_set_doc,
" Specifies the orientation of front-facing polygons.\n"
"\n"
" :param invert: True for clockwise polygons as front-facing.\n"
- " :type mode: `bool`\n");
+ " :type mode: bool\n");
static PyObject *pygpu_state_front_facing_set(PyObject *UNUSED(self), PyObject *value)
{
bool invert;
@@ -326,7 +321,7 @@ PyDoc_STRVAR(pygpu_state_program_point_size_set_doc,
"shader builtin gl_PointSize.\n"
"\n"
" :param enable: True for shader builtin gl_PointSize.\n"
- " :type enable: `bool`\n");
+ " :type enable: bool\n");
static PyObject *pygpu_state_program_point_size_set(PyObject *UNUSED(self), PyObject *value)
{
bool enable;
diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c
index 14f901624fe..1ae65c1dd11 100644
--- a/source/blender/python/gpu/gpu_py_texture.c
+++ b/source/blender/python/gpu/gpu_py_texture.c
@@ -272,21 +272,17 @@ static PyObject *pygpu_texture_format_get(BPyGPUTexture *self, void *UNUSED(type
return PyUnicode_FromString(PyC_StringEnum_FindIDFromValue(pygpu_textureformat_items, format));
}
-PyDoc_STRVAR(pygpu_texture_clear_doc,
- ".. method:: clear(format='FLOAT', value=(0.0, 0.0, 0.0, 1.0))\n"
- "\n"
- " Fill texture with specific value.\n"
- "\n"
- " :param format: One of these primitive types: {\n"
- " `FLOAT`,\n"
- " `INT`,\n"
- " `UINT`,\n"
- " `UBYTE`,\n"
- " `UINT_24_8`,\n"
- " `10_11_11_REV`,\n"
- " :type type: `str`\n"
- " :arg value: sequence each representing the value to fill.\n"
- " :type value: sequence of 1, 2, 3 or 4 values\n");
+PyDoc_STRVAR(
+ pygpu_texture_clear_doc,
+ ".. method:: clear(format='FLOAT', value=(0.0, 0.0, 0.0, 1.0))\n"
+ "\n"
+ " Fill texture with specific value.\n"
+ "\n"
+ " :param format: The format that describes the content of a single item.\n"
+ " Possible values are `FLOAT`, `INT`, `UINT`, `UBYTE`, `UINT_24_8` and `10_11_11_REV`.\n"
+ " :type type: str\n"
+ " :arg value: sequence each representing the value to fill.\n"
+ " :type value: sequence of 1, 2, 3 or 4 values\n");
static PyObject *pygpu_texture_clear(BPyGPUTexture *self, PyObject *args, PyObject *kwds)
{
BPYGPU_TEXTURE_CHECK_OBJ(self);
@@ -447,12 +443,12 @@ PyDoc_STRVAR(
" This object gives access to off GPU textures.\n"
"\n"
" :arg size: Dimensions of the texture 1D, 2D, 3D or cubemap.\n"
- " :type size: `tuple` or `int`\n"
+ " :type size: tuple or int\n"
" :arg layers: Number of layers in texture array or number of cubemaps in cubemap array\n"
- " :type layers: `int`\n"
+ " :type layers: int\n"
" :arg is_cubemap: Indicates the creation of a cubemap texture.\n"
- " :type is_cubemap: `int`\n"
- " :arg format: One of these primitive types: {\n"
+ " :type is_cubemap: int\n"
+ " :arg format: Internal data format inside GPU memory. Possible values are:\n"
" `RGBA8UI`,\n"
" `RGBA8I`,\n"
" `RGBA8`,\n"
@@ -497,9 +493,9 @@ PyDoc_STRVAR(
" `DEPTH_COMPONENT32F`,\n"
" `DEPTH_COMPONENT24`,\n"
" `DEPTH_COMPONENT16`,\n"
- " :type format: `str`\n"
+ " :type format: str\n"
" :arg data: Buffer object to fill the texture.\n"
- " :type data: `Buffer`\n");
+ " :type data: :class:`gpu.types.Buffer`\n");
PyTypeObject BPyGPUTexture_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUTexture",
.tp_basicsize = sizeof(BPyGPUTexture),
diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c
index c60d6216834..edcec486398 100644
--- a/source/blender/python/gpu/gpu_py_uniformbuffer.c
+++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c
@@ -161,7 +161,7 @@ PyDoc_STRVAR(pygpu_uniformbuffer__tp_doc,
" This object gives access to off uniform buffers.\n"
"\n"
" :arg data: Buffer object.\n"
- " :type data: `Buffer`\n");
+ " :type data: :class:`gpu.types.Buffer`\n");
PyTypeObject BPyGPUUniformBuf_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUUniformBuf",
.tp_basicsize = sizeof(BPyGPUUniformBuf),
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c
index dcea57e78dc..111fa114c43 100644
--- a/source/blender/python/gpu/gpu_py_vertex_buffer.c
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c
@@ -271,7 +271,7 @@ PyDoc_STRVAR(pygpu_vertbuf_attr_fill_doc,
" :param id: Either the name or the id of the attribute.\n"
" :type id: int or str\n"
" :param data: Sequence of data that should be stored in the buffer\n"
- " :type data: sequence of values or tuples\n");
+ " :type data: sequence of floats, ints, vectors or matrices\n");
static PyObject *pygpu_vertbuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds)
{
PyObject *data;
diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c
index 343cf06b20a..39c91966cab 100644
--- a/source/blender/python/gpu/gpu_py_vertex_format.c
+++ b/source/blender/python/gpu/gpu_py_vertex_format.c
@@ -85,7 +85,7 @@ PyDoc_STRVAR(
" :type id: str\n"
" :param comp_type: The data type that will be used store the value in memory.\n"
" Possible values are `I8`, `U8`, `I16`, `U16`, `I32`, `U32`, `F32` and `I10`.\n"
- " :type comp_type: `str`\n"
+ " :type comp_type: str\n"
" :param len: How many individual values the attribute consists of\n"
" (e.g. 2 for uv coordinates).\n"
" :type len: int\n"
@@ -94,7 +94,7 @@ PyDoc_STRVAR(
" reduced precision. E.g. you can store a float in only 1 byte but it will be\n"
" converted to a normal 4 byte float when used.\n"
" Possible values are `FLOAT`, `INT`, `INT_TO_FLOAT_UNIT` and `INT_TO_FLOAT`.\n"
- " :type fetch_mode: `str`\n");
+ " :type fetch_mode: str\n");
static PyObject *pygpu_vertformat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds)
{
const char *id;
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 5d8330e368d..c7816aed3c1 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -75,6 +75,7 @@ set(SRC
bpy_rna_anim.c
bpy_rna_array.c
bpy_rna_callback.c
+ bpy_rna_data.c
bpy_rna_driver.c
bpy_rna_gizmo.c
bpy_rna_id_collection.c
@@ -113,6 +114,7 @@ set(SRC
bpy_rna.h
bpy_rna_anim.h
bpy_rna_callback.h
+ bpy_rna_data.h
bpy_rna_driver.h
bpy_rna_gizmo.h
bpy_rna_id_collection.h
@@ -278,10 +280,22 @@ if(WITH_JACK)
add_definitions(-DWITH_JACK)
endif()
+if(WITH_COREAUDIO)
+ add_definitions(-DWITH_COREAUDIO)
+endif()
+
if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
+if(WITH_PULSEAUDIO)
+ add_definitions(-DWITH_PULSEAUDIO)
+endif()
+
+if(WITH_WASAPI)
+ add_definitions(-DWITH_WASAPI)
+endif()
+
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 74fc8bcfec9..547cf2ad38f 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -44,6 +44,7 @@
#include "bpy_operator.h"
#include "bpy_props.h"
#include "bpy_rna.h"
+#include "bpy_rna_data.h"
#include "bpy_rna_gizmo.h"
#include "bpy_rna_id_collection.h"
#include "bpy_rna_types_capi.h"
@@ -425,6 +426,8 @@ void BPy_init_modules(struct bContext *C)
/* needs to be first so bpy_types can run */
BPY_library_load_type_ready();
+ BPY_rna_data_context_type_ready();
+
BPY_rna_gizmo_module(mod);
bpy_import_test("bpy_types");
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index c7e195b586d..927ec11c376 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -216,7 +216,7 @@ static PyObject *make_app_info(void)
#undef SetObjItem
if (PyErr_Occurred()) {
- Py_CLEAR(app_info);
+ Py_DECREF(app_info);
return NULL;
}
return app_info;
diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c
index d5640045977..bb218c57d06 100644
--- a/source/blender/python/intern/bpy_app_alembic.c
+++ b/source/blender/python/intern/bpy_app_alembic.c
@@ -79,8 +79,8 @@ static PyObject *make_alembic_info(void)
SetStrItem("Unknown");
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(alembic_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(alembic_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index aaceb7b393f..f7b71c769d1 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -49,7 +49,10 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"opensubdiv", NULL},
{"sdl", NULL},
{"sdl_dynload", NULL},
+ {"coreaudio", NULL},
{"jack", NULL},
+ {"pulseaudio", NULL},
+ {"wasapi", NULL},
{"libmv", NULL},
{"mod_oceansim", NULL},
{"mod_remesh", NULL},
@@ -211,12 +214,30 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_COREAUDIO
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_JACK
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
+#ifdef WITH_PULSEAUDIO
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_WASAPI
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_LIBMV
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c
index 4e396668450..d2261ee7311 100644
--- a/source/blender/python/intern/bpy_app_ffmpeg.c
+++ b/source/blender/python/intern/bpy_app_ffmpeg.c
@@ -116,8 +116,8 @@ static PyObject *make_ffmpeg_info(void)
#undef FFMPEG_LIB_VERSION
- if (PyErr_Occurred()) {
- Py_CLEAR(ffmpeg_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(ffmpeg_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c
index 3a36e90018f..8ce87bd0150 100644
--- a/source/blender/python/intern/bpy_app_ocio.c
+++ b/source/blender/python/intern/bpy_app_ocio.c
@@ -81,8 +81,8 @@ static PyObject *make_ocio_info(void)
SetStrItem("Unknown");
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(ocio_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(ocio_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c
index 0038f982170..8436296680b 100644
--- a/source/blender/python/intern/bpy_app_oiio.c
+++ b/source/blender/python/intern/bpy_app_oiio.c
@@ -77,8 +77,8 @@ static PyObject *make_oiio_info(void)
SetStrItem("Unknown");
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(oiio_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(oiio_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c
index 90aab2a4500..635013a1f9e 100644
--- a/source/blender/python/intern/bpy_app_opensubdiv.c
+++ b/source/blender/python/intern/bpy_app_opensubdiv.c
@@ -74,8 +74,8 @@ static PyObject *make_opensubdiv_info(void)
SetStrItem("Unknown");
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(opensubdiv_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(opensubdiv_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c
index c98c6ec0137..20a61ba170a 100644
--- a/source/blender/python/intern/bpy_app_openvdb.c
+++ b/source/blender/python/intern/bpy_app_openvdb.c
@@ -81,8 +81,8 @@ static PyObject *make_openvdb_info(void)
SetStrItem("Unknown");
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(openvdb_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(openvdb_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c
index 645119c1c5d..e45e73fb4de 100644
--- a/source/blender/python/intern/bpy_app_sdl.c
+++ b/source/blender/python/intern/bpy_app_sdl.c
@@ -114,8 +114,8 @@ static PyObject *make_sdl_info(void)
SetObjItem(PyBool_FromLong(0));
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(sdl_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(sdl_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_app_usd.c b/source/blender/python/intern/bpy_app_usd.c
index 4a0ee96061a..72287d45b93 100644
--- a/source/blender/python/intern/bpy_app_usd.c
+++ b/source/blender/python/intern/bpy_app_usd.c
@@ -80,8 +80,8 @@ static PyObject *make_usd_info(void)
SetStrItem("Unknown");
#endif
- if (PyErr_Occurred()) {
- Py_CLEAR(usd_info);
+ if (UNLIKELY(PyErr_Occurred())) {
+ Py_DECREF(usd_info);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index c5f5e9c71b8..5f31e0bb74d 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -45,6 +45,7 @@
#include "bpy_capi_utils.h"
#include "bpy_intern_string.h"
#include "bpy_path.h"
+#include "bpy_props.h"
#include "bpy_rna.h"
#include "bpy_traceback.h"
@@ -304,6 +305,7 @@ static struct _inittab bpy_internal_modules[] = {
{NULL, NULL},
};
+#ifndef WITH_PYTHON_MODULE
/**
* Convenience function for #BPY_python_start.
*
@@ -321,6 +323,7 @@ static void pystatus_exit_on_error(PyStatus status)
Py_ExitStatusException(status);
}
}
+#endif
/* call BPY_context_set first */
void BPY_python_start(bContext *C, int argc, const char **argv)
@@ -521,6 +524,9 @@ void BPY_python_end(void)
/* finalizing, no need to grab the state, except when we are a module */
gilstate = PyGILState_Ensure();
+ /* Decrement user counts of all callback functions. */
+ BPY_rna_props_clear_all();
+
/* free other python data. */
pyrna_free_types();
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 020c8f7ea49..96ff6a111d9 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -68,9 +68,13 @@ typedef struct {
BlendHandle *blo_handle;
int flag;
PyObject *dict;
+ /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries.
+ * Defaults to #G.main, Otherwise use a temporary #Main when `bmain_is_temp` is true. */
+ Main *bmain;
+ bool bmain_is_temp;
} BPy_Library;
-static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds);
+static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds);
static PyObject *bpy_lib_enter(BPy_Library *self);
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args);
static PyObject *bpy_lib_dir(BPy_Library *self);
@@ -114,8 +118,8 @@ static PyTypeObject bpy_lib_Type = {
NULL, /* reprfunc tp_str; */
/* will only use these if this is a subtype of a py class */
- NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
+ PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
@@ -182,9 +186,10 @@ PyDoc_STRVAR(
" :type relative: bool\n"
" :arg assets_only: If True, only list data-blocks marked as assets.\n"
" :type assets_only: bool\n");
-static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
{
- Main *bmain = CTX_data_main(BPY_context_get());
+ Main *bmain_base = CTX_data_main(BPY_context_get());
+ Main *bmain = self->ptr.data; /* Typically #G_MAIN */
BPy_Library *ret;
const char *filename = NULL;
bool is_rel = false, is_link = false, use_assets_only = false;
@@ -210,11 +215,14 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *
BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain));
+ ret->bmain = bmain;
+ ret->bmain_is_temp = (bmain != bmain_base);
+
ret->blo_handle = NULL;
ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) |
(use_assets_only ? FILE_ASSETS_ONLY : 0));
- ret->dict = _PyDict_NewPresized(MAX_LIBARRAY);
+ ret->dict = _PyDict_NewPresized(INDEX_ID_MAX);
return (PyObject *)ret;
}
@@ -245,7 +253,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self)
{
PyObject *ret;
BPy_Library *self_from;
- PyObject *from_dict = _PyDict_NewPresized(MAX_LIBARRAY);
+ PyObject *from_dict = _PyDict_NewPresized(INDEX_ID_MAX);
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
@@ -333,7 +341,7 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
- Main *bmain = CTX_data_main(BPY_context_get());
+ Main *bmain = self->bmain;
Main *mainl = NULL;
const int err = 0;
const bool do_append = ((self->flag & FILE_LINK) == 0);
@@ -341,8 +349,9 @@ 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 */
+ const int id_tag_extra = self->bmain_is_temp ? LIB_TAG_TEMP_MAIN : 0;
struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init(&liblink_params, bmain, self->flag);
+ BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
@@ -369,6 +378,12 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
ID *id = BLO_library_link_named_part(
mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
if (id) {
+
+ if (self->bmain_is_temp) {
+ /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
+ BLI_assert(id->tag & LIB_TAG_TEMP_MAIN);
+ }
+
#ifdef USE_RNA_DATABLOCKS
/* swap name for pointer to the id */
item_dst = PyCapsule_New((void *)id, NULL, NULL);
@@ -477,16 +492,12 @@ static PyObject *bpy_lib_dir(BPy_Library *self)
PyMethodDef BPY_library_load_method_def = {
"load",
(PyCFunction)bpy_lib_load,
- METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ METH_VARARGS | METH_KEYWORDS,
bpy_lib_load_doc,
};
int BPY_library_load_type_ready(void)
{
-
- /* some compilers don't like accessing this directly, delay assignment */
- bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr;
-
if (PyType_Ready(&bpy_lib_Type) < 0) {
return -1;
}
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index 66d20dd357f..f26f305cca8 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -71,7 +71,7 @@ PyDoc_STRVAR(
" :type fake_user: bool\n"
" :arg compress: When True, write a compressed blend file.\n"
" :type compress: bool\n");
-static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+static PyObject *bpy_lib_write(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
{
/* args */
const char *filepath;
@@ -114,7 +114,7 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject
return NULL;
}
- Main *bmain_src = G_MAIN;
+ Main *bmain_src = self->ptr.data; /* Typically #G_MAIN */
int write_flags = 0;
if (use_compress) {
@@ -220,6 +220,6 @@ finally:
PyMethodDef BPY_library_write_method_def = {
"write",
(PyCFunction)bpy_lib_write,
- METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ METH_VARARGS | METH_KEYWORDS,
bpy_lib_write_doc,
};
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 967eece4bcb..94ad6a8ef78 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -17,12 +17,12 @@
/** \file
* \ingroup pythonintern
*
- * This file defines '_bpy.ops', an internal python module which gives python
- * the ability to inspect and call both C and Python defined operators.
+ * This file defines `_bpy.ops`, an internal python module which gives Python
+ * the ability to inspect and call operators (defined by C or Python).
*
* \note
- * This module is exposed to the user via 'release/scripts/modules/bpy/ops.py'
- * which fakes exposing operators as modules/functions using its own classes.
+ * This C module is private, it should only be used by `release/scripts/modules/bpy/ops.py` which
+ * exposes operators as dynamically defined modules & callable objects to access all operators.
*/
#include <Python.h>
@@ -38,7 +38,7 @@
#include "bpy_capi_utils.h"
#include "bpy_operator.h"
#include "bpy_operator_wrap.h"
-#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
+#include "bpy_rna.h" /* for setting argument properties & type method `get_rna_type`. */
#include "RNA_access.h"
#include "RNA_enum_types.h"
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index 5137f41d43a..c2d7257e458 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup pythonintern
*
- * This file is so python can define operators that C can call into.
+ * This file exposes functionality for defining to define operators that C can call into.
* The generic callback functions for python operators are defines in
* 'rna_wm.c', some calling into functions here to do python specific
* functionality.
@@ -115,6 +115,10 @@ static void operator_properties_init(wmOperatorType *ot)
/* end 'ot->prop' assignment */
}
+/**
+ * Generic function used by all Python defined operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
@@ -131,6 +135,10 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
+/**
+ * Generic function used by all Python defined macro-operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index b2812e0eba7..e4e6b3ea8f2 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -29,6 +29,7 @@
#include "RNA_types.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "bpy_capi_utils.h"
@@ -47,14 +48,9 @@
#include "../generic/py_capi_utils.h"
-/* initial definition of callback slots we'll probably have more than 1 */
-enum {
- BPY_DATA_CB_SLOT_UPDATE = 0,
- BPY_DATA_CB_SLOT_GET = 1,
- BPY_DATA_CB_SLOT_SET = 2,
- BPY_DATA_CB_SLOT_POLL = 3,
- BPY_DATA_CB_SLOT_SIZE = 4,
-};
+/* -------------------------------------------------------------------- */
+/** \name Shared Enums & Doc-Strings
+ * \{ */
static const EnumPropertyItem property_flag_items[] = {
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
@@ -193,6 +189,123 @@ static const EnumPropertyItem property_subtype_array_items[] = {
"'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \
" :type subtype: string\n"
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Python Property Storage API
+ *
+ * Functionality needed to use Python native callbacks from generic C RNA callbacks.
+ * \{ */
+
+/**
+ * Store #PyObject data for a dynamically defined property.
+ * Currently this is only used to store call-back functions.
+ * Properties that don't use custom-callbacks wont allocate this struct.
+ *
+ * Memory/Reference Management
+ * ---------------------------
+ *
+ * This struct adds/removes the user-count of each #PyObject it references,
+ * it's needed in case the function is removed from the class (unlikely but possible),
+ * also when an annotation evaluates to a `lambda` with Python 3.10 and newer e.g: T86332.
+ *
+ * Pointers to this struct are held in:
+ *
+ * - #PropertyRNA.py_data (owns the memory).
+ * Freed when the RNA property is freed.
+ *
+ * - #g_bpy_prop_store_list (borrows the memory)
+ * Having a global list means the users can be visited by the GC and cleared on exit.
+ *
+ * This list can't be used for freeing as #BPyPropStore doesn't hold a #PropertyRNA back-pointer,
+ * (while it could be supported it would only complicate things).
+ *
+ * All RNA properties are freed after Python has been shut-down.
+ * At that point Python user counts can't be touched and must have already been dealt with.
+ *
+ * Decrementing users is handled by:
+ *
+ * - #bpy_prop_py_data_remove manages decrementing at run-time (when a property is removed),
+ *
+ * - #BPY_rna_props_clear_all does this on exit for all dynamic properties.
+ */
+struct BPyPropStore {
+ struct BPyPropStore *next, *prev;
+
+ /**
+ * Only store #PyObject types, so this member can be cast to an array and iterated over.
+ * NULL members are skipped.
+ */
+ struct {
+ /** Wrap: `RNA_def_property_*_funcs` (depending on type). */
+ PyObject *get_fn;
+ PyObject *set_fn;
+ /** Wrap: #RNA_def_property_update_runtime */
+ PyObject *update_fn;
+
+ /** Arguments by type. */
+ union {
+ /** #PROP_ENUM type. */
+ struct {
+ /** Wrap: #RNA_def_property_enum_funcs_runtime */
+ PyObject *itemf_fn;
+ } enum_data;
+ /** #PROP_POINTER type. */
+ struct {
+ /** Wrap: #RNA_def_property_poll_runtime */
+ PyObject *poll_fn;
+ } pointer_data;
+ };
+ } py_data;
+};
+
+#define BPY_PROP_STORE_PY_DATA_SIZE \
+ (sizeof(((struct BPyPropStore *)NULL)->py_data) / sizeof(PyObject *))
+
+#define ASSIGN_PYOBJECT_INCREF(a, b) \
+ { \
+ BLI_assert((a) == NULL); \
+ Py_INCREF(b); \
+ a = b; \
+ } \
+ ((void)0)
+
+/**
+ * Maintain a list of Python defined properties, so the GC can visit them,
+ * and so they can be cleared on exit.
+ */
+static ListBase g_bpy_prop_store_list = {NULL, NULL};
+
+static struct BPyPropStore *bpy_prop_py_data_ensure(struct PropertyRNA *prop)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ if (prop_store == NULL) {
+ prop_store = MEM_callocN(sizeof(*prop_store), __func__);
+ RNA_def_py_data(prop, prop_store);
+ BLI_addtail(&g_bpy_prop_store_list, prop_store);
+ }
+ return prop_store;
+}
+
+/**
+ * Perform all removal actions except for freeing, which is handled by RNA.
+ */
+static void bpy_prop_py_data_remove(PropertyRNA *prop)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ if (prop_store == NULL) {
+ return;
+ }
+
+ PyObject **py_data = (PyObject **)&prop_store->py_data;
+ for (int i = 0; i < BPY_PROP_STORE_PY_DATA_SIZE; i++) {
+ Py_XDECREF(py_data[i]);
+ }
+ BLI_remlink(&g_bpy_prop_store_list, prop_store);
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Deferred Property Type
*
@@ -203,10 +316,8 @@ static const EnumPropertyItem property_subtype_array_items[] = {
static void bpy_prop_deferred_dealloc(BPy_PropDeferred *self)
{
- if (self->kw) {
- PyObject_GC_UnTrack(self);
- Py_CLEAR(self->kw);
- }
+ PyObject_GC_UnTrack(self);
+ Py_CLEAR(self->kw);
PyObject_GC_Del(self);
}
@@ -368,20 +479,28 @@ static void bpy_prop_assign_flag_override(PropertyRNA *prop, const int flag_over
RNA_def_property_override_flag(prop, flag_override);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shared Property Callbacks
+ *
+ * Unique data is accessed via #RNA_property_py_data_get
+ * \{ */
+
/* callbacks */
-static void bpy_prop_update_cb(struct bContext *C,
+static void bpy_prop_update_fn(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop)
{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyGILState_STATE gilstate;
- PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
PyObject *ret;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -389,7 +508,7 @@ static void bpy_prop_update_cb(struct bContext *C,
bpy_context_set(C, &gilstate);
- py_func = py_data[BPY_DATA_CB_SLOT_UPDATE];
+ py_func = prop_store->py_data.update_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -421,9 +540,15 @@ static void bpy_prop_update_cb(struct bContext *C,
}
}
-static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Boolean Property Callbacks
+ * \{ */
+
+static bool bpy_prop_boolean_get_fn(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -433,7 +558,7 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *
const bool is_write_ok = pyrna_write_check();
bool value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -445,7 +570,7 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -484,9 +609,9 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *
return value;
}
-static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, bool value)
+static void bpy_prop_boolean_set_fn(struct PointerRNA *ptr, struct PropertyRNA *prop, bool value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -495,7 +620,7 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -507,7 +632,7 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -540,60 +665,11 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
}
}
-static bool bpy_prop_poll_cb(struct PointerRNA *self,
- PointerRNA candidate,
- struct PropertyRNA *prop)
-{
- PyObject *py_self;
- PyObject *py_candidate;
- PyObject *py_func;
- PyObject **py_data = RNA_property_py_data_get(prop);
- PyObject *args;
- PyObject *ret;
- bool result;
- const int is_write_ok = pyrna_write_check();
- const PyGILState_STATE gilstate = PyGILState_Ensure();
-
- BLI_assert(self != NULL);
-
- py_self = pyrna_struct_as_instance(self);
- py_candidate = pyrna_struct_as_instance(&candidate);
- py_func = py_data[BPY_DATA_CB_SLOT_POLL];
-
- if (!is_write_ok) {
- pyrna_write_set(true);
- }
-
- args = PyTuple_New(2);
- PyTuple_SET_ITEM(args, 0, py_self);
- PyTuple_SET_ITEM(args, 1, py_candidate);
-
- ret = PyObject_CallObject(py_func, args);
-
- Py_DECREF(args);
-
- if (ret == NULL) {
- PyC_Err_PrintWithFunc(py_func);
- result = false;
- }
- else {
- result = PyObject_IsTrue(ret);
- Py_DECREF(ret);
- }
-
- PyGILState_Release(gilstate);
- if (!is_write_ok) {
- pyrna_write_set(false);
- }
-
- return result;
-}
-
-static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
+static void bpy_prop_boolean_array_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -603,7 +679,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
int i, len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -615,7 +691,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -656,11 +732,11 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
}
}
-static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
+static void bpy_prop_boolean_array_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const bool *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -671,7 +747,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
const int len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -683,7 +759,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -717,9 +793,15 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
}
}
-static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Int Property Callbacks
+ * \{ */
+
+static int bpy_prop_int_get_fn(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -729,7 +811,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
const bool is_write_ok = pyrna_write_check();
int value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -741,7 +823,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -777,9 +859,9 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
return value;
}
-static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
+static void bpy_prop_int_set_fn(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -788,7 +870,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -800,7 +882,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -833,11 +915,11 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
}
}
-static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
+static void bpy_prop_int_array_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
int *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -847,7 +929,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
int i, len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -859,7 +941,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -900,11 +982,11 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
}
}
-static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
+static void bpy_prop_int_array_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const int *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -915,7 +997,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
const int len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -927,7 +1009,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -961,9 +1043,15 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
}
}
-static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Float Property Callbacks
+ * \{ */
+
+static float bpy_prop_float_get_fn(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -973,7 +1061,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
const bool is_write_ok = pyrna_write_check();
float value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -985,7 +1073,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1021,9 +1109,9 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
return value;
}
-static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float value)
+static void bpy_prop_float_set_fn(struct PointerRNA *ptr, struct PropertyRNA *prop, float value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1032,7 +1120,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1044,7 +1132,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1077,11 +1165,11 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
}
}
-static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
+static void bpy_prop_float_array_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
float *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1091,7 +1179,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
int i, len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1103,7 +1191,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1144,11 +1232,11 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
}
}
-static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
+static void bpy_prop_float_array_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const float *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1159,7 +1247,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
const int len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1171,7 +1259,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1205,9 +1293,15 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
}
}
-static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Property Callbacks
+ * \{ */
+
+static void bpy_prop_string_get_fn(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1216,7 +1310,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1228,7 +1322,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1265,9 +1359,9 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
}
}
-static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
+static int bpy_prop_string_length_fn(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1277,7 +1371,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
const bool is_write_ok = pyrna_write_check();
int length;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1289,7 +1383,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1328,11 +1422,11 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
return length;
}
-static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
+static void bpy_prop_string_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const char *value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1342,7 +1436,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
PyObject *py_value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1354,7 +1448,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1394,9 +1488,70 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
}
}
-static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pointer Property Callbacks
+ * \{ */
+
+static bool bpy_prop_pointer_poll_fn(struct PointerRNA *self,
+ PointerRNA candidate,
+ struct PropertyRNA *prop)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ PyObject *py_self;
+ PyObject *py_candidate;
+ PyObject *py_func;
+ PyObject *args;
+ PyObject *ret;
+ bool result;
+ const int is_write_ok = pyrna_write_check();
+ const PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ BLI_assert(self != NULL);
+
+ py_self = pyrna_struct_as_instance(self);
+ py_candidate = pyrna_struct_as_instance(&candidate);
+ py_func = prop_store->py_data.pointer_data.poll_fn;
+
+ if (!is_write_ok) {
+ pyrna_write_set(true);
+ }
+
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 0, py_self);
+ PyTuple_SET_ITEM(args, 1, py_candidate);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ result = false;
+ }
+ else {
+ result = PyObject_IsTrue(ret);
+ Py_DECREF(ret);
+ }
+
+ PyGILState_Release(gilstate);
+ if (!is_write_ok) {
+ pyrna_write_set(false);
+ }
+
+ return result;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Enum Property Callbacks
+ * \{ */
+
+static int bpy_prop_enum_get_fn(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1406,7 +1561,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
const bool is_write_ok = pyrna_write_check();
int value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1418,7 +1573,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1454,9 +1609,9 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
return value;
}
-static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
+static void bpy_prop_enum_set_fn(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1465,7 +1620,7 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1477,7 +1632,7 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1728,14 +1883,14 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
return items;
}
-static const EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C,
+static const EnumPropertyItem *bpy_prop_enum_itemf_fn(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
bool *r_free)
{
PyGILState_STATE gilstate;
-
- PyObject *py_func = RNA_property_enum_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ PyObject *py_func = prop_store->py_data.enum_data.itemf_fn;
PyObject *self = NULL;
PyObject *args;
PyObject *items; /* returned from the function call */
@@ -1838,244 +1993,243 @@ static int bpy_prop_callback_check(PyObject *py_func, const char *keyword, int a
return 0;
}
-static PyObject **bpy_prop_py_data_get(struct PropertyRNA *prop)
-{
- PyObject **py_data = RNA_property_py_data_get(prop);
- if (!py_data) {
- py_data = MEM_callocN(sizeof(PyObject *) * BPY_DATA_CB_SLOT_SIZE, __func__);
- RNA_def_py_data(prop, py_data);
- }
- return py_data;
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shared Callback Assignment
+ * \{ */
-static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *update_cb)
+static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *update_fn)
{
/* assume this is already checked for type and arg length */
- if (update_cb && update_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (update_fn && update_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- RNA_def_property_update_runtime(prop, (void *)bpy_prop_update_cb);
- py_data[BPY_DATA_CB_SLOT_UPDATE] = update_cb;
+ RNA_def_property_update_runtime(prop, bpy_prop_update_fn);
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.update_fn, update_fn);
RNA_def_property_flag(prop, PROP_CONTEXT_PROPERTY_UPDATE);
}
}
-static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_cb)
+static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_fn)
{
- if (poll_cb && poll_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (poll_fn && poll_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- RNA_def_property_poll_runtime(prop, (void *)bpy_prop_poll_cb);
- py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb;
+ RNA_def_property_poll_runtime(prop, bpy_prop_pointer_poll_fn);
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.pointer_data.poll_fn, poll_fn);
}
}
static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- BooleanPropertyGetFunc rna_get_cb = NULL;
- BooleanPropertySetFunc rna_set_cb = NULL;
+ BooleanPropertyGetFunc rna_get_fn = NULL;
+ BooleanPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_boolean_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_boolean_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_boolean_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_boolean_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_boolean_funcs_runtime(prop, rna_get_cb, rna_set_cb);
+ RNA_def_property_boolean_funcs_runtime(prop, rna_get_fn, rna_set_fn);
}
static void bpy_prop_callback_assign_boolean_array(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- BooleanArrayPropertyGetFunc rna_get_cb = NULL;
- BooleanArrayPropertySetFunc rna_set_cb = NULL;
+ BooleanArrayPropertyGetFunc rna_get_fn = NULL;
+ BooleanArrayPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_boolean_array_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_boolean_array_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_boolean_array_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_boolean_array_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_boolean_array_funcs_runtime(prop, rna_get_cb, rna_set_cb);
+ RNA_def_property_boolean_array_funcs_runtime(prop, rna_get_fn, rna_set_fn);
}
static void bpy_prop_callback_assign_int(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- IntPropertyGetFunc rna_get_cb = NULL;
- IntPropertySetFunc rna_set_cb = NULL;
+ IntPropertyGetFunc rna_get_fn = NULL;
+ IntPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_int_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_int_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_int_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_int_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_int_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
+ RNA_def_property_int_funcs_runtime(prop, rna_get_fn, rna_set_fn, NULL);
}
static void bpy_prop_callback_assign_int_array(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- IntArrayPropertyGetFunc rna_get_cb = NULL;
- IntArrayPropertySetFunc rna_set_cb = NULL;
+ IntArrayPropertyGetFunc rna_get_fn = NULL;
+ IntArrayPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_int_array_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_int_array_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_int_array_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_int_array_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_int_array_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
+ RNA_def_property_int_array_funcs_runtime(prop, rna_get_fn, rna_set_fn, NULL);
}
static void bpy_prop_callback_assign_float(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- FloatPropertyGetFunc rna_get_cb = NULL;
- FloatPropertySetFunc rna_set_cb = NULL;
+ FloatPropertyGetFunc rna_get_fn = NULL;
+ FloatPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_float_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_float_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_float_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_float_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_float_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
+ RNA_def_property_float_funcs_runtime(prop, rna_get_fn, rna_set_fn, NULL);
}
static void bpy_prop_callback_assign_float_array(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- FloatArrayPropertyGetFunc rna_get_cb = NULL;
- FloatArrayPropertySetFunc rna_set_cb = NULL;
+ FloatArrayPropertyGetFunc rna_get_fn = NULL;
+ FloatArrayPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_float_array_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_float_array_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_float_array_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_float_array_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_float_array_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
+ RNA_def_property_float_array_funcs_runtime(prop, rna_get_fn, rna_set_fn, NULL);
}
static void bpy_prop_callback_assign_string(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb)
+ PyObject *get_fn,
+ PyObject *set_fn)
{
- StringPropertyGetFunc rna_get_cb = NULL;
- StringPropertyLengthFunc rna_length_cb = NULL;
- StringPropertySetFunc rna_set_cb = NULL;
+ StringPropertyGetFunc rna_get_fn = NULL;
+ StringPropertyLengthFunc rna_length_fn = NULL;
+ StringPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_string_get_cb;
- rna_length_cb = bpy_prop_string_length_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_string_get_fn;
+ rna_length_fn = bpy_prop_string_length_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_string_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_string_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- RNA_def_property_string_funcs_runtime(prop, rna_get_cb, rna_length_cb, rna_set_cb);
+ RNA_def_property_string_funcs_runtime(prop, rna_get_fn, rna_length_fn, rna_set_fn);
}
static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
- PyObject *get_cb,
- PyObject *set_cb,
- PyObject *itemf_cb)
+ PyObject *get_fn,
+ PyObject *set_fn,
+ PyObject *itemf_fn)
{
- EnumPropertyGetFunc rna_get_cb = NULL;
- EnumPropertyItemFunc rna_itemf_cb = NULL;
- EnumPropertySetFunc rna_set_cb = NULL;
+ EnumPropertyGetFunc rna_get_fn = NULL;
+ EnumPropertyItemFunc rna_itemf_fn = NULL;
+ EnumPropertySetFunc rna_set_fn = NULL;
- if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (get_fn && get_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_get_cb = bpy_prop_enum_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ rna_get_fn = bpy_prop_enum_get_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_fn);
}
- if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ if (set_fn && set_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- rna_set_cb = bpy_prop_enum_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ rna_set_fn = bpy_prop_enum_set_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
- if (itemf_cb && itemf_cb != Py_None) {
- rna_itemf_cb = bpy_prop_enum_itemf_cb;
- RNA_def_property_enum_py_data(prop, (void *)itemf_cb);
-
- /* watch out!, if a user is tricky they can probably crash blender
- * if they manage to free the callback, take care! */
- /* Py_INCREF(itemf_cb); */
+ if (itemf_fn && itemf_fn != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
+ rna_itemf_fn = bpy_prop_enum_itemf_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.enum_data.itemf_fn, itemf_fn);
}
- RNA_def_property_enum_funcs_runtime(prop, rna_get_cb, rna_set_cb, rna_itemf_cb);
+ RNA_def_property_enum_funcs_runtime(prop, rna_get_fn, rna_set_fn, rna_itemf_fn);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shared Method Utilities
+ * \{ */
+
/* this define runs at the start of each function and deals with
* returning a deferred property (to be registered later) */
#define BPY_PROPDEF_HEAD(_func) \
@@ -2155,6 +2309,12 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
} \
(void)0
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shared Method Doc-Strings
+ * \{ */
+
#define BPY_PROPDEF_NAME_DOC \
" :arg name: Name used in the user interface.\n" \
" :type name: string\n"
@@ -2241,6 +2401,12 @@ static int bpy_struct_id_used(StructRNA *srna, char *identifier)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module Methods
+ * \{ */
+
/* Function that sets RNA, NOTE - self is NULL when called from python,
* but being abused from C so we can pass the srna along.
* This isn't incorrect since its a python object - but be careful */
@@ -2279,9 +2445,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -2315,9 +2481,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&py_tags,
&pysubtype,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -2326,13 +2492,13 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
property_flag_override_items,
property_subtype_number_items);
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -2349,8 +2515,8 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_boolean(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_boolean(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
@@ -2397,9 +2563,9 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -2434,9 +2600,9 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
&py_tags,
&pysubtype,
&size,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -2459,13 +2625,13 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
return NULL;
}
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -2489,8 +2655,8 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_boolean_array(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_boolean_array(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
@@ -2538,9 +2704,9 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -2583,9 +2749,9 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&py_tags,
&pysubtype,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -2594,13 +2760,13 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
property_flag_override_items,
property_subtype_number_items);
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -2619,8 +2785,8 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_int(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_int(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -2674,9 +2840,9 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -2721,9 +2887,9 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
&py_tags,
&pysubtype,
&size,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -2746,13 +2912,13 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
return NULL;
}
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -2774,8 +2940,8 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_int_array(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_int_array(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -2829,9 +2995,9 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
int subtype = PROP_NONE;
const char *pyunit = NULL;
int unit = PROP_UNIT_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -2862,9 +3028,9 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
&py_tags,
&pysubtype,
&pyunit,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -2878,13 +3044,13 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -2903,8 +3069,8 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_float(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_float(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -2962,9 +3128,9 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
int subtype = PROP_NONE;
const char *pyunit = NULL;
int unit = PROP_UNIT_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -2996,9 +3162,9 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
&pysubtype,
&pyunit,
&size,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -3027,13 +3193,13 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
return NULL;
}
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -3055,8 +3221,8 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_float_array(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_float_array(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -3101,9 +3267,9 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -3138,9 +3304,9 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
&PySet_Type,
&py_tags,
&pysubtype,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
@@ -3149,13 +3315,13 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
property_flag_override_items,
property_subtype_string_items);
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -3178,8 +3344,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_string(prop, get_cb, set_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_string(prop, get_fn, set_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -3260,9 +3426,9 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
int opts_override = 0;
int prop_tags = 0;
bool is_itemf = false;
- PyObject *update_cb = NULL;
- PyObject *get_cb = NULL;
- PyObject *set_cb = NULL;
+ PyObject *update_fn = NULL;
+ PyObject *get_fn = NULL;
+ PyObject *set_fn = NULL;
PyObject *py_tags = NULL;
static const char *_keywords[] = {
@@ -3295,21 +3461,21 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
&pyopts_override,
&PySet_Type,
&py_tags,
- &update_cb,
- &get_cb,
- &set_cb)) {
+ &update_fn,
+ &get_fn,
+ &set_fn)) {
return NULL;
}
BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items, property_flag_override_items);
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(get_cb, "get", 1) == -1) {
+ if (bpy_prop_callback_check(get_fn, "get", 1) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(set_cb, "set", 2) == -1) {
+ if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
@@ -3376,8 +3542,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts_override) {
bpy_prop_assign_flag_override(prop, opts_override);
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_enum(prop, get_cb, set_cb, (is_itemf ? items : NULL));
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_enum(prop, get_fn, set_fn, (is_itemf ? items : NULL));
RNA_def_property_duplicate_pointers(srna, prop);
if (is_itemf == false) {
@@ -3448,7 +3614,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
int opts = 0;
int opts_override = 0;
int prop_tags = 0;
- PyObject *update_cb = NULL, *poll_cb = NULL;
+ PyObject *update_fn = NULL, *poll_fn = NULL;
static const char *_keywords[] = {
"attr",
@@ -3477,8 +3643,8 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
&pyopts_override,
&PySet_Type,
&py_tags,
- &poll_cb,
- &update_cb)) {
+ &poll_fn,
+ &update_fn)) {
return NULL;
}
@@ -3495,10 +3661,10 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
RNA_struct_ui_name(&RNA_PropertyGroup));
return NULL;
}
- if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ if (bpy_prop_callback_check(update_fn, "update", 2) == -1) {
return NULL;
}
- if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) {
+ if (bpy_prop_callback_check(poll_fn, "poll", 2) == -1) {
return NULL;
}
prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description);
@@ -3517,8 +3683,8 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
}
}
- bpy_prop_callback_assign_update(prop, update_cb);
- bpy_prop_callback_assign_pointer(prop, poll_cb);
+ bpy_prop_callback_assign_update(prop, update_fn);
+ bpy_prop_callback_assign_pointer(prop, poll_fn);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -3676,6 +3842,12 @@ static PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Module `bpy.props`
+ * \{ */
+
static struct PyMethodDef props_methods[] = {
{"BoolProperty",
(PyCFunction)BPy_BoolProperty,
@@ -3725,6 +3897,28 @@ static struct PyMethodDef props_methods[] = {
{NULL, NULL, 0, NULL},
};
+static int props_visit(PyObject *UNUSED(self), visitproc visit, void *arg)
+{
+ LISTBASE_FOREACH (struct BPyPropStore *, prop_store, &g_bpy_prop_store_list) {
+ PyObject **py_data = (PyObject **)&prop_store->py_data;
+ for (int i = 0; i < BPY_PROP_STORE_PY_DATA_SIZE; i++) {
+ Py_VISIT(py_data[i]);
+ }
+ }
+ return 0;
+}
+
+static int props_clear(PyObject *UNUSED(self))
+{
+ LISTBASE_FOREACH (struct BPyPropStore *, prop_store, &g_bpy_prop_store_list) {
+ PyObject **py_data = (PyObject **)&prop_store->py_data;
+ for (int i = 0; i < BPY_PROP_STORE_PY_DATA_SIZE; i++) {
+ Py_CLEAR(py_data[i]);
+ }
+ }
+ return 0;
+}
+
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpy.props",
@@ -3737,8 +3931,8 @@ static struct PyModuleDef props_module = {
-1, /* multiple "initialization" just copies the module dict. */
props_methods,
NULL,
- NULL,
- NULL,
+ props_visit,
+ props_clear,
NULL,
};
@@ -3772,5 +3966,26 @@ PyObject *BPY_rna_props(void)
}
PyModule_AddType(submodule, &bpy_prop_deferred_Type);
+ /* Run this when properties are freed. */
+ RNA_def_property_free_pointers_set_py_data_callback(bpy_prop_py_data_remove);
+
return submodule;
}
+
+/**
+ * Run this on exit, clearing all Python callback users and disable the RNA callback,
+ * as it would be called after Python has already finished.
+ */
+void BPY_rna_props_clear_all(void)
+{
+ /* Remove all user counts, so this isn't considered a leak from Python's perspective. */
+ props_clear(NULL);
+
+ /* Running is harmless, but redundant. */
+ RNA_def_property_free_pointers_set_py_data_callback(NULL);
+
+ /* Include as it's correct, in practice this should never be used again. */
+ BLI_listbase_clear(&g_bpy_prop_store_list);
+}
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index 6cebf82d373..d467166f354 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -25,6 +25,7 @@ extern "C" {
#endif
PyObject *BPY_rna_props(void);
+void BPY_rna_props_clear_all(void);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 189d8308c14..fab73d0f3dc 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1204,15 +1204,15 @@ static void pyrna_struct_dealloc(BPy_StructRNA *self)
static void pyrna_struct_reference_set(BPy_StructRNA *self, PyObject *reference)
{
if (self->reference) {
- // PyObject_GC_UnTrack(self); /* INITIALIZED TRACKED ? */
- pyrna_struct_clear(self);
+ PyObject_GC_UnTrack(self);
+ Py_CLEAR(self->reference);
}
/* Reference is now NULL. */
if (reference) {
self->reference = reference;
Py_INCREF(reference);
- // PyObject_GC_Track(self); /* INITIALIZED TRACKED ? */
+ PyObject_GC_Track(self);
}
}
#endif /* !USE_PYRNA_STRUCT_REFERENCE */
@@ -2022,45 +2022,67 @@ static int pyrna_py_to_prop(
}
}
- if (!BPy_StructRNA_Check(value) && value != Py_None) {
- PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s expected a %.200s type, not %.200s",
- error_prefix,
- RNA_struct_identifier(ptr->type),
- RNA_property_identifier(prop),
- RNA_struct_identifier(ptr_type),
- Py_TYPE(value)->tp_name);
- Py_XDECREF(value_new);
- return -1;
- }
- if ((flag & PROP_NEVER_NULL) && value == Py_None) {
- PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s does not support a 'None' assignment %.200s type",
- error_prefix,
- RNA_struct_identifier(ptr->type),
- RNA_property_identifier(prop),
- RNA_struct_identifier(ptr_type));
- Py_XDECREF(value_new);
- return -1;
+ BPy_StructRNA *param;
+ if (value == Py_None) {
+ if (flag & PROP_NEVER_NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s %.200s.%.200s does not support a 'None' assignment %.200s type",
+ error_prefix,
+ RNA_struct_identifier(ptr->type),
+ RNA_property_identifier(prop),
+ RNA_struct_identifier(ptr_type));
+ Py_XDECREF(value_new);
+ return -1;
+ }
+ param = NULL;
}
- if ((value != Py_None) && ((flag & PROP_ID_SELF_CHECK) &&
- ptr->owner_id == ((BPy_StructRNA *)value)->ptr.owner_id)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s ID type does not support assignment to itself",
- error_prefix,
- RNA_struct_identifier(ptr->type),
- RNA_property_identifier(prop));
- Py_XDECREF(value_new);
- return -1;
+ else {
+ if (!BPy_StructRNA_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s %.200s.%.200s expected a %.200s type, not %.200s",
+ error_prefix,
+ RNA_struct_identifier(ptr->type),
+ RNA_property_identifier(prop),
+ RNA_struct_identifier(ptr_type),
+ Py_TYPE(value)->tp_name);
+ Py_XDECREF(value_new);
+ return -1;
+ }
+ param = (BPy_StructRNA *)value;
+
+ const ID *value_owner_id = ((BPy_StructRNA *)value)->ptr.owner_id;
+ if (value_owner_id != NULL) {
+ if ((flag & PROP_ID_SELF_CHECK) && (ptr->owner_id == value_owner_id)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s %.200s.%.200s ID type does not support assignment to itself",
+ error_prefix,
+ RNA_struct_identifier(ptr->type),
+ RNA_property_identifier(prop));
+ Py_XDECREF(value_new);
+ return -1;
+ }
+
+ if (value_owner_id->tag & LIB_TAG_TEMP_MAIN) {
+ /* Allow passing temporary ID's to functions, but not attribute assignment. */
+ if (ptr->type != &RNA_Function) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s %.200s.%.200s ID type assignment is temporary, can't assign",
+ error_prefix,
+ RNA_struct_identifier(ptr->type),
+ RNA_property_identifier(prop));
+ Py_XDECREF(value_new);
+ return -1;
+ }
+ }
+ }
}
- BPy_StructRNA *param = (BPy_StructRNA *)value;
bool raise_error = false;
if (data) {
if (flag_parameter & PARM_RNAPTR) {
if (flag & PROP_THICK_WRAP) {
- if (value == Py_None) {
+ if (param == NULL) {
memset(data, 0, sizeof(PointerRNA));
}
else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
@@ -2075,7 +2097,7 @@ static int pyrna_py_to_prop(
* but watch out that it remains valid!
* We could possibly support this later if needed. */
BLI_assert(value_new == NULL);
- if (value == Py_None) {
+ if (param == NULL) {
*((void **)data) = NULL;
}
else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
@@ -2086,7 +2108,7 @@ static int pyrna_py_to_prop(
}
}
}
- else if (value == Py_None) {
+ else if (param == NULL) {
*((void **)data) = NULL;
}
else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
@@ -2098,11 +2120,11 @@ static int pyrna_py_to_prop(
}
else {
/* Data == NULL, assign to RNA. */
- if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type)) {
+ if ((param == NULL) || RNA_struct_is_a(param->ptr.type, ptr_type)) {
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
RNA_property_pointer_set(
- ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr, &reports);
+ ptr, prop, (param == NULL) ? PointerRNA_NULL : param->ptr, &reports);
const int err = (BPy_reports_to_error(&reports, PyExc_RuntimeError, true));
if (err == -1) {
Py_XDECREF(value_new);
@@ -4589,13 +4611,12 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject
#else
{
/* Could just do this except for 1 awkward case.
- * PyObject_GenericGetAttr((PyObject *)self, pyname);
- * so as to support 'bpy.data.library.load()'
- * note, this _only_ supports static methods */
+ * `PyObject_GenericGetAttr((PyObject *)self, pyname);`
+ * so as to support `bpy.data.library.load()` */
PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, pyname);
- if (ret == NULL && name[0] != '_') { /* Avoid inheriting __call__ and similar. */
+ if (ret == NULL && name[0] != '_') { /* Avoid inheriting `__call__` and similar. */
/* Since this is least common case, handle it last. */
PointerRNA r_ptr;
if (RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) {
@@ -4613,6 +4634,19 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject
if (ret == NULL) {
PyErr_Restore(error_type, error_value, error_traceback);
}
+ else {
+ if (Py_TYPE(ret) == &PyMethodDescr_Type) {
+ PyMethodDef *m = ((PyMethodDescrObject *)ret)->d_method;
+ /* TODO: #METH_CLASS */
+ if (m->ml_flags & METH_STATIC) {
+ /* Keep 'ret' as-is. */
+ }
+ else {
+ Py_DECREF(ret);
+ ret = PyCMethod_New(m, (PyObject *)self, NULL, NULL);
+ }
+ }
+ }
}
}
@@ -5813,6 +5847,11 @@ static PyObject *pyrna_struct_new(PyTypeObject *type, PyObject *args, PyObject *
BPy_StructRNA *ret;
if ((ret = (BPy_StructRNA *)type->tp_alloc(type, 0))) {
ret->ptr = base->ptr;
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ /* #PyType_GenericAlloc will have set tracking.
+ * We only want tracking when `StructRNA.reference` has been set. */
+ PyObject_GC_UnTrack(ret);
+#endif
}
/* Pass on exception & NULL if tp_alloc fails. */
return (PyObject *)ret;
@@ -6516,7 +6555,11 @@ PyTypeObject pyrna_struct_Type = {
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ | Py_TPFLAGS_HAVE_GC
+#endif
+ , /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
@@ -7035,13 +7078,9 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
-/* will only use these if this is a subtype of a py class */
-# if defined(_MSC_VER)
- NULL, /* defer assignment */
-# else
+ /* will only use these if this is a subtype of a py class */
PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */
-# endif
- NULL, /* setattrofunc tp_setattro; */
+ NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
@@ -7067,13 +7106,9 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
# else
0,
# endif
-/*** Added in release 2.2 ***/
-/* Iterators */
-# if defined(_MSC_VER)
- NULL, /* defer assignment */
-# else
- PyObject_SelfIter, /* getiterfunc tp_iter; */
-# endif
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ PyObject_SelfIter, /* getiterfunc tp_iter; */
(iternextfunc)pyrna_prop_collection_iter_next, /* iternextfunc tp_iternext; */
/*** Attribute descriptor and subclassing stuff ***/
@@ -7453,13 +7488,28 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr)
if (tp) {
pyrna = (BPy_StructRNA *)tp->tp_alloc(tp, 0);
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ /* #PyType_GenericAlloc will have set tracking.
+ * We only want tracking when `StructRNA.reference` has been set. */
+ if (pyrna != NULL) {
+ PyObject_GC_UnTrack(pyrna);
+ }
+#endif
Py_DECREF(tp); /* srna owns, can't hold a reference. */
}
else {
CLOG_WARN(BPY_LOG_RNA, "could not make type '%s'", RNA_struct_identifier(ptr->type));
+
+#ifdef USE_PYRNA_STRUCT_REFERENCE
pyrna = (BPy_StructRNA *)PyObject_GC_New(BPy_StructRNA, &pyrna_struct_Type);
+#else
+ pyrna = (BPy_StructRNA *)PyObject_New(BPy_StructRNA, &pyrna_struct_Type);
+#endif
+
#ifdef USE_WEAKREFS
- pyrna->in_weakreflist = NULL;
+ if (pyrna != NULL) {
+ pyrna->in_weakreflist = NULL;
+ }
#endif
}
}
@@ -7582,9 +7632,6 @@ void BPY_rna_init(void)
/* For some reason MSVC complains of these. */
#if defined(_MSC_VER)
pyrna_struct_meta_idprop_Type.tp_base = &PyType_Type;
-
- pyrna_prop_collection_iter_Type.tp_iter = PyObject_SelfIter;
- pyrna_prop_collection_iter_Type.tp_getattro = PyObject_GenericGetAttr;
#endif
/* metaclass */
@@ -8961,7 +9008,7 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
#if 0
if (PyDict_GetItem(((PyTypeObject *)py_class)->tp_dict, bpy_intern_str_bl_rna) == NULL) {
- PWM_cursor_wait(0);
+ PWM_cursor_wait(false);
PyErr_SetString(PyExc_ValueError, "unregister_class(): not a registered as a subclass");
return NULL;
}
diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c
new file mode 100644
index 00000000000..daab1631e8e
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_data.c
@@ -0,0 +1,219 @@
+/*
+ * 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 pythonintern
+ *
+ * This file defines the API to support temporarily creating #Main data.
+ * The only use case for this is currently to support temporarily loading data-blocks
+ * which can be freed, without them polluting the current #G_MAIN.
+ *
+ * This is exposed via a context manager `bpy.types.BlendData.temp_data(...)`
+ * which returns a new `bpy.types.BlendData` that is freed once the context manager exits.
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+
+#include "bpy_rna.h"
+#include "bpy_rna_data.h"
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ BPy_StructRNA *data_rna;
+ char filepath[1024];
+} BPy_DataContext;
+
+static PyObject *bpy_rna_data_temp_data(PyObject *self, PyObject *args, PyObject *kwds);
+static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self);
+static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *args);
+
+static PyMethodDef bpy_rna_data_context_methods[] = {
+ {"__enter__", (PyCFunction)bpy_rna_data_context_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)bpy_rna_data_context_exit, METH_VARARGS},
+ {NULL} /* sentinel */
+};
+
+static int bpy_rna_data_context_traverse(BPy_DataContext *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->data_rna);
+ return 0;
+}
+
+static int bpy_rna_data_context_clear(BPy_DataContext *self)
+{
+ Py_CLEAR(self->data_rna);
+ return 0;
+}
+
+static void bpy_rna_data_context_dealloc(BPy_DataContext *self)
+{
+ PyObject_GC_UnTrack(self);
+ Py_CLEAR(self->data_rna);
+ PyObject_GC_Del(self);
+}
+
+static PyTypeObject bpy_rna_data_context_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0) "bpy_rna_data_context", /* tp_name */
+ sizeof(BPy_DataContext), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)bpy_rna_data_context_dealloc, /* tp_dealloc */
+ 0, /* tp_vectorcall_offset */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL,
+ /* tp_compare */ /* DEPRECATED in python 3.0! */
+ NULL, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+
+ /* will only use these if this is a subtype of a py class */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ (traverseproc)bpy_rna_data_context_traverse, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ (inquiry)bpy_rna_data_context_clear, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons (subclassed) ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0,
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ bpy_rna_data_context_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL,
+};
+
+PyDoc_STRVAR(bpy_rna_data_context_load_doc,
+ ".. method:: temp_data(filepath=None)\n"
+ "\n"
+ " A context manager that temporarily creates blender file data.\n"
+ "\n"
+ " :arg filepath: The file path for the newly temporary data. "
+ "When None, the path of the currently open file is used.\n"
+ " :type filepath: str or NoneType\n"
+ "\n"
+ " :return: Blend file data which is freed once the context exists.\n"
+ " :rtype: :class:`bpy.types.BlendData`\n");
+
+static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ BPy_DataContext *ret;
+ const char *filepath = NULL;
+ static const char *_keywords[] = {"filepath", NULL};
+ static _PyArg_Parser _parser = {"|$z:temp_data", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) {
+ return NULL;
+ }
+
+ ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type);
+
+ STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name);
+
+ return (PyObject *)ret;
+}
+
+static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self)
+{
+ Main *bmain_temp = BKE_main_new();
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_BlendData, bmain_temp, &ptr);
+
+ self->data_rna = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr);
+
+ PyObject_GC_Track(self);
+
+ return (PyObject *)self->data_rna;
+}
+
+static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *UNUSED(args))
+{
+ BKE_main_free(self->data_rna->ptr.data);
+ RNA_POINTER_INVALIDATE(&self->data_rna->ptr);
+ Py_RETURN_NONE;
+}
+
+PyMethodDef BPY_rna_data_context_method_def = {
+ "temp_data",
+ (PyCFunction)bpy_rna_data_temp_data,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_rna_data_context_load_doc,
+};
+
+int BPY_rna_data_context_type_ready(void)
+{
+ if (PyType_Ready(&bpy_rna_data_context_Type) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/intern/bpy_rna_data.h b/source/blender/python/intern/bpy_rna_data.h
new file mode 100644
index 00000000000..b1d226d9dc4
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_data.h
@@ -0,0 +1,29 @@
+/*
+ * 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 pythonintern
+ */
+
+#pragma once
+
+int BPY_rna_data_context_type_ready(void);
+
+extern PyMethodDef BPY_rna_data_context_method_def;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index 042f7b6fd67..9b15e84663d 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -36,6 +36,7 @@
#include "bpy_library.h"
#include "bpy_rna.h"
#include "bpy_rna_callback.h"
+#include "bpy_rna_data.h"
#include "bpy_rna_id_collection.h"
#include "bpy_rna_types_capi.h"
#include "bpy_rna_ui.h"
@@ -56,6 +57,7 @@ static struct PyMethodDef pyrna_blenddata_methods[] = {
{NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */
{NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */
{NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_data_context_method_def */
{NULL, NULL, 0, NULL},
};
@@ -207,8 +209,9 @@ void BPY_rna_types_extend_capi(void)
ARRAY_SET_ITEMS(pyrna_blenddata_methods,
BPY_rna_id_collection_user_map_method_def,
BPY_rna_id_collection_batch_remove_method_def,
- BPY_rna_id_collection_orphans_purge_method_def);
- BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4);
+ BPY_rna_id_collection_orphans_purge_method_def,
+ BPY_rna_data_context_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 5);
pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL);
/* BlendDataLibraries */
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index 1859886f563..cba4628b63a 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -658,10 +658,10 @@ static void get_ccgdm_data(DerivedMesh *lodm,
/* get the original cage face index */
int cage_face_index = index_mp_to_orig ? index_mp_to_orig[poly_index] : poly_index;
/* local offset in total cage face grids
- * (1 << (2 * lvl)) is number of all polys for one cage face */
- int loc_cage_poly_offs = poly_index % (1 << (2 * lvl));
+ * `(1 << (2 * lvl))` is number of all polys for one cage face */
+ int loc_cage_poly_ofs = poly_index % (1 << (2 * lvl));
/* local offset in the vertex grid itself */
- int cell_index = loc_cage_poly_offs % (polys_per_grid_side * polys_per_grid_side);
+ int cell_index = loc_cage_poly_ofs % (polys_per_grid_side * polys_per_grid_side);
int cell_side = (grid_size - 1) / polys_per_grid_side;
/* row and column based on grid side */
int row = cell_index / polys_per_grid_side;
@@ -1193,7 +1193,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV);
MAOBakeData *ao_data = (MAOBakeData *)bake_data;
- int i, k, perm_offs;
+ int i, k, perm_ofs;
float pos[3], nrm[3];
float cen[3];
float axisX[3], axisY[3], axisZ[3];
@@ -1236,7 +1236,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
build_coordinate_frame(axisX, axisY, axisZ);
/* static noise */
- perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);
+ perm_ofs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);
/* importance sample shadow rays (cosine weighted) */
for (i = 0; i < ao_data->number_of_rays; i++) {
@@ -1246,12 +1246,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
* a multi-dimensional domain (2D)
*/
const unsigned short I =
- ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays];
+ ao_data->permutation_table_1[(i + perm_ofs) % ao_data->number_of_rays];
const unsigned short J = ao_data->permutation_table_2[i];
- const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
+ const float JitPh = (get_ao_random2(I + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
((float)MAX_NUMBER_OF_AO_RAYS);
- const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
+ const float JitTh = (get_ao_random1(J + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
((float)MAX_NUMBER_OF_AO_RAYS);
const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays;
const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays);
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index b0ab20de10d..bea9dfbb0ed 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -555,10 +555,10 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->noisebasis);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs,
+ texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->mg_H,
@@ -566,7 +566,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->mg_octaves,
tex->noisebasis);
texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->mg_H,
tex->mg_lacunarity,
@@ -574,7 +574,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->noisebasis);
texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->mg_H,
tex->mg_lacunarity,
tex->mg_octaves,
@@ -612,10 +612,10 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->noisebasis);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs,
+ texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->mg_H,
@@ -625,7 +625,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->mg_gain,
tex->noisebasis);
texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->mg_H,
tex->mg_lacunarity,
@@ -635,7 +635,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->noisebasis);
texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->mg_H,
tex->mg_lacunarity,
tex->mg_octaves,
@@ -666,10 +666,10 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->noisebasis);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + offs,
+ texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->mg_H,
@@ -678,7 +678,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->mg_offset,
tex->noisebasis);
texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->mg_H,
tex->mg_lacunarity,
@@ -687,7 +687,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->noisebasis);
texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->mg_H,
tex->mg_lacunarity,
tex->mg_octaves,
@@ -711,24 +711,24 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex
texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + offs,
+ texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->dist_amount,
tex->noisebasis,
tex->noisebasis2);
texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->dist_amount,
tex->noisebasis,
tex->noisebasis2);
texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->dist_amount,
tex->noisebasis,
tex->noisebasis2);
@@ -805,14 +805,14 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
}
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- BLI_noise_voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm);
+ BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
tex_normal_derivate(tex, texres);
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index 82e303806b3..9d9553ed858 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -72,6 +72,7 @@ set(SRC
intern/multiview.h
intern/prefetch.c
intern/prefetch.h
+ intern/proxy_job.c
intern/proxy.c
intern/proxy.h
intern/render.c
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index e262d7ed1ef..7d728b25a30 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -30,7 +30,6 @@ extern "C" {
struct ListBase;
struct Scene;
struct Sequence;
-struct bContext;
/* SeqLoadData.flags */
typedef enum eSeqLoadFlags {
diff --git a/source/blender/sequencer/SEQ_proxy.h b/source/blender/sequencer/SEQ_proxy.h
index 6934215839f..b06adef2802 100644
--- a/source/blender/sequencer/SEQ_proxy.h
+++ b/source/blender/sequencer/SEQ_proxy.h
@@ -35,6 +35,7 @@ struct Main;
struct Scene;
struct SeqIndexBuildContext;
struct Sequence;
+struct SeqRenderData;
bool SEQ_proxy_rebuild_context(struct Main *bmain,
struct Depsgraph *depsgraph,
@@ -48,10 +49,21 @@ void SEQ_proxy_rebuild(struct SeqIndexBuildContext *context,
float *progress);
void SEQ_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
void SEQ_proxy_set(struct Sequence *seq, bool value);
-bool SEQ_can_use_proxy(struct Sequence *seq, int psize);
+bool SEQ_can_use_proxy(const struct SeqRenderData *context, struct Sequence *seq, int psize);
int SEQ_rendersize_to_proxysize(int render_size);
double SEQ_rendersize_to_scale_factor(int size);
+typedef struct ProxyBuildJob {
+ struct Main *main;
+ struct Depsgraph *depsgraph;
+ struct Scene *scene;
+ struct ListBase queue;
+ int stop;
+} ProxyJob;
+
+struct wmJob *ED_seq_proxy_wm_job_get(const struct bContext *C);
+ProxyJob *ED_seq_proxy_job_get(const struct bContext *C, struct wmJob *wm_job);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h
index 54584824da8..c138daf1318 100644
--- a/source/blender/sequencer/SEQ_render.h
+++ b/source/blender/sequencer/SEQ_render.h
@@ -44,6 +44,7 @@ typedef struct SeqRenderData {
int rectx;
int recty;
int preview_render_size;
+ bool use_proxies;
int for_render;
int motion_blur_samples;
float motion_blur_shutter;
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 22d8daba696..a0e6bc7f4f1 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -55,6 +55,7 @@
#include "IMB_metadata.h"
#include "SEQ_proxy.h"
+#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
@@ -199,11 +200,12 @@ static bool seq_proxy_get_fname(Editing *ed,
return true;
}
-bool SEQ_can_use_proxy(Sequence *seq, int psize)
+bool SEQ_can_use_proxy(const struct SeqRenderData *context, Sequence *seq, int psize)
{
- if (seq->strip->proxy == NULL) {
+ if (seq->strip->proxy == NULL || !context->use_proxies) {
return false;
}
+
short size_flags = seq->strip->proxy->build_size_flags;
return (seq->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE && (size_flags & psize) != 0;
}
@@ -217,7 +219,7 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline
StripAnim *sanim;
/* only use proxies, if they are enabled (even if present!) */
- if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(psize))) {
+ if (!SEQ_can_use_proxy(context, seq, SEQ_rendersize_to_proxysize(psize))) {
return NULL;
}
@@ -394,6 +396,17 @@ static int seq_proxy_context_count(Sequence *seq, Scene *scene)
return num_views;
}
+static bool seq_proxy_need_rebuild(Sequence *seq, struct anim *anim)
+{
+ if ((seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0) {
+ return true;
+ }
+
+ IMB_Proxy_Size required_proxies = seq->strip->proxy->build_size_flags;
+ IMB_Proxy_Size built_proxies = IMB_anim_proxy_get_existing(anim);
+ return (required_proxies & built_proxies) != required_proxies;
+}
+
bool SEQ_proxy_rebuild_context(Main *bmain,
Depsgraph *depsgraph,
Scene *scene,
@@ -422,6 +435,16 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
continue;
}
+ /* Check if proxies are already built here, because actually opening anims takes a lot of
+ * time. */
+ seq_open_anim_file(scene, seq, false);
+ StripAnim *sanim = BLI_findlink(&seq->anims, i);
+ if (sanim->anim && !seq_proxy_need_rebuild(seq, sanim->anim)) {
+ continue;
+ }
+
+ SEQ_relations_sequence_free_anim(seq);
+
context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
nseq = SEQ_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
@@ -440,28 +463,25 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
context->view_id = i; /* only for images */
if (nseq->type == SEQ_TYPE_MOVIE) {
- StripAnim *sanim;
-
seq_open_anim_file(scene, nseq, true);
sanim = BLI_findlink(&nseq->anims, i);
- if (sanim->anim) {
- context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
- context->tc_flags,
- context->size_flags,
- context->quality,
- context->overwrite,
- file_list);
- }
- if (!context->index_context) {
- MEM_freeN(context);
- return false;
- }
+ context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
+ context->tc_flags,
+ context->size_flags,
+ context->quality,
+ context->overwrite,
+ file_list);
+ }
+ if (!context->index_context) {
+ SEQ_proxy_rebuild_finish(context, false);
+ return false;
}
link = BLI_genericNodeN(context);
BLI_addtail(queue, link);
}
+
return true;
}
diff --git a/source/blender/sequencer/intern/proxy_job.c b/source/blender/sequencer/intern/proxy_job.c
new file mode 100644
index 00000000000..aea66da4cc4
--- /dev/null
+++ b/source/blender/sequencer/intern/proxy_job.c
@@ -0,0 +1,121 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_timecode.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "SEQ_iterator.h"
+#include "SEQ_proxy.h"
+#include "SEQ_relations.h"
+#include "SEQ_sequencer.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_define.h"
+
+static void proxy_freejob(void *pjv)
+{
+ ProxyJob *pj = pjv;
+
+ BLI_freelistN(&pj->queue);
+
+ MEM_freeN(pj);
+}
+
+/* Only this runs inside thread. */
+static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
+{
+ ProxyJob *pj = pjv;
+ LinkData *link;
+
+ for (link = pj->queue.first; link; link = link->next) {
+ struct SeqIndexBuildContext *context = link->data;
+
+ SEQ_proxy_rebuild(context, stop, do_update, progress);
+
+ if (*stop) {
+ pj->stop = 1;
+ fprintf(stderr, "Canceling proxy rebuild on users request...\n");
+ break;
+ }
+ }
+}
+
+static void proxy_endjob(void *pjv)
+{
+ ProxyJob *pj = pjv;
+ Editing *ed = SEQ_editing_get(pj->scene, false);
+ LinkData *link;
+
+ for (link = pj->queue.first; link; link = link->next) {
+ SEQ_proxy_rebuild_finish(link->data, pj->stop);
+ }
+
+ SEQ_relations_free_imbuf(pj->scene, &ed->seqbase, false);
+
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
+}
+
+ProxyJob *ED_seq_proxy_job_get(const bContext *C, wmJob *wm_job)
+{
+ Scene *scene = CTX_data_scene(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ProxyJob *pj = WM_jobs_customdata_get(wm_job);
+ if (!pj) {
+ pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
+ pj->depsgraph = depsgraph;
+ pj->scene = scene;
+ pj->main = CTX_data_main(C);
+ WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
+ WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
+ }
+ return pj;
+}
+
+struct wmJob *ED_seq_proxy_wm_job_get(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Building Proxies",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_SEQ_BUILD_PROXY);
+ return wm_job;
+}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index cf07fc7bc19..73d12bfd6b6 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -1121,7 +1121,7 @@ static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context,
IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
- if (SEQ_can_use_proxy(seq, psize)) {
+ if (SEQ_can_use_proxy(context, seq, psize)) {
/* Try to get a proxy image.
* Movie proxies are handled by ImBuf module with exception of `custom file` setting. */
if (context->scene->ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE &&
@@ -1793,7 +1793,8 @@ ImBuf *seq_render_strip(const SeqRenderData *context,
}
/* Proxies are not stored in cache. */
- if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(context->preview_render_size))) {
+ if (!SEQ_can_use_proxy(
+ context, seq, SEQ_rendersize_to_proxysize(context->preview_render_size))) {
ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW);
}
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 8bb0bf8fb63..4db7350544b 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -357,7 +357,7 @@ void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase)
}
/**
- * Create and initialize MetaStack, append it to ed->metastack ListBase
+ * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
*
* \param ed: sequence editor data
* \param seq_meta: meta strip
@@ -374,7 +374,7 @@ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
}
/**
- * Free MetaStack and remoove it from ed->metastack ListBase
+ * Free #MetaStack and remove it from `ed->metastack` ListBase.
*
* \param ed: sequence editor data
* \param ms: meta stack
@@ -386,7 +386,7 @@ void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
}
/**
- * Get MetaStack that coresponds to current level that is being viewed
+ * Get #MetaStack that corresponds to current level that is being viewed
*
* \param ed: sequence editor data
* \return pointer to meta stack
diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c
index 9a86e1e96f5..8a259c6aaff 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.c
+++ b/source/blender/shader_fx/intern/FX_ui_common.c
@@ -241,14 +241,9 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt))
*/
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw)
{
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- /* Get the name for the effect's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- BKE_shaderfxType_panel_id(type, panel_idname);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BKE_shaderfxType_panel_id(type, panel_type->idname);
BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -282,13 +277,9 @@ PanelType *shaderfx_subpanel_register(ARegionType *region_type,
PanelDrawFn draw,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 545371f4540..9f70d05cc8a 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -755,6 +755,7 @@ enum {
WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE,
WM_JOB_TYPE_QUADRIFLOW_REMESH,
WM_JOB_TYPE_TRACE_IMAGE,
+ WM_JOB_TYPE_LINEART,
/* add as needed, bake, seq proxy build
* if having hard coded values is a problem */
};
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 863a4436e04..385a572ab85 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -287,6 +287,9 @@ typedef struct wmNotifier {
#define NC_TEXT (12 << 24)
#define NC_WORLD (13 << 24)
#define NC_ANIMATION (14 << 24)
+/* When passing a space as reference data with this (e.g. `WM_event_add_notifier(..., space)`),
+ * the notifier will only be sent to this space. That avoids unnecessary updates for unrelated
+ * spaces. */
#define NC_SPACE (15 << 24)
#define NC_GEOM (16 << 24)
#define NC_NODE (17 << 24)
@@ -427,6 +430,7 @@ typedef struct wmNotifier {
#define ND_SPACE_CHANGED (19 << 16) /*sent to a new editor type after it's replaced an old one*/
#define ND_SPACE_CLIP (20 << 16)
#define ND_SPACE_FILE_PREVIEW (21 << 16)
+#define ND_SPACE_SPREADSHEET (22 << 16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00
@@ -461,6 +465,7 @@ typedef struct wmNotifier {
#define NA_SELECTED 6
#define NA_ACTIVATED 7
#define NA_PAINTING 8
+#define NA_JOB_FINISHED 9
/* ************** Gesture Manager data ************** */
@@ -612,10 +617,6 @@ typedef struct wmEvent {
/** Raw-key modifier (allow using any key as a modifier). */
short keymodifier;
- /** Set in case a #KM_PRESS went by unhandled. */
- char check_click;
- char check_drag;
-
/** Tablet info, available for mouse move and button events. */
wmTabletData tablet;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 051e3e4c1a9..9b38f010205 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -1258,9 +1258,6 @@ void wm_gizmomaptypes_free(void)
*/
void wm_gizmos_keymap(wmKeyConfig *keyconf)
{
- /* we add this item-less keymap once and use it to group gizmo-group keymaps into it */
- WM_keymap_ensure(keyconf, "Gizmos", 0, 0);
-
LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) {
wm_gizmogrouptype_setup_keymap(gzgt_ref->type, keyconf);
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index a9c0d1dd8fe..ae5b6c468f7 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -20,7 +20,7 @@
/** \file
* \ingroup wm
*
- * Internal functions for managing UI registrable types (operator, UI and menu types).
+ * Internal functions for managing UI registerable types (operator, UI and menu types).
*
* Also Blender's main event loop (WM_main).
*/
@@ -172,7 +172,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
win->ime_data = NULL;
#endif
- BLI_listbase_clear(&win->queue);
+ BLI_listbase_clear(&win->event_queue);
BLI_listbase_clear(&win->handlers);
BLI_listbase_clear(&win->modalhandlers);
BLI_listbase_clear(&win->gesture);
@@ -184,6 +184,8 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
win->modalcursor = 0;
win->grabcursor = 0;
win->addmousemove = true;
+ win->event_queue_check_click = 0;
+ win->event_queue_check_drag = 0;
BLO_read_data_address(reader, &win->stereo3d_format);
/* Multi-view always fallback to anaglyph at file opening
@@ -198,7 +200,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
BLI_listbase_clear(&wm->timers);
BLI_listbase_clear(&wm->operators);
BLI_listbase_clear(&wm->paintcursors);
- BLI_listbase_clear(&wm->queue);
+ BLI_listbase_clear(&wm->notifier_queue);
BKE_reports_init(&wm->reports, RPT_STORE);
BLI_listbase_clear(&wm->keyconfigs);
@@ -471,7 +473,10 @@ void WM_keyconfig_init(bContext *C)
wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT;
}
- WM_keyconfig_update_tag(NULL, NULL);
+ /* Harmless, but no need to update in background mode. */
+ if (!G.background) {
+ WM_keyconfig_update_tag(NULL, NULL);
+ }
WM_keyconfig_update(wm);
wm->initialized |= WM_KEYCONFIG_IS_INIT;
@@ -565,7 +570,7 @@ void wm_add_default(Main *bmain, bContext *C)
void wm_close_and_free(bContext *C, wmWindowManager *wm)
{
if (wm->autosavetimer) {
- wm_autosave_timer_ended(wm);
+ wm_autosave_timer_end(wm);
}
#ifdef WITH_XR_OPENXR
@@ -590,7 +595,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
WM_keyconfig_free(keyconf);
}
- BLI_freelistN(&wm->queue);
+ BLI_freelistN(&wm->notifier_queue);
if (wm->message_bus != NULL) {
WM_msgbus_destroy(wm->message_bus);
@@ -640,10 +645,10 @@ void WM_main(bContext *C)
/* Per window, all events to the window, screen, area and region handlers. */
wm_event_do_handlers(C);
- /* Wvents have left notes about changes, we handle and cache it. */
+ /* Events have left notes about changes, we handle and cache it. */
wm_event_do_notifiers(C);
- /* Wxecute cached changes draw. */
+ /* Execute cached changes draw. */
wm_draw_update(C);
}
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index e32552063af..cdb7b591907 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -303,7 +303,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
{
/* note: don't use wmEvent coords because of continuous grab T36409. */
int cx, cy;
- wm_get_cursor_position(win, &cx, &cy);
+ wm_cursor_position_get(win, &cx, &cy);
WM_cursor_warp(win, cx + x, cy + y);
}
@@ -520,13 +520,37 @@ void wm_init_cursor_data(void)
BlenderCursor[WM_CURSOR_WAIT] = &WaitCursor;
END_CURSOR_BLOCK;
+ /********************** Mute Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+ static char mute_bitmap[] = {
+ 0x00, 0x00, 0x22, 0x00, 0x14, 0x00, 0x08, 0x03, 0x14, 0x03, 0x22,
+ 0x03, 0x00, 0x03, 0x00, 0x03, 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00,
+ };
+
+ static char mute_mask[] = {
+ 0x63, 0x00, 0x77, 0x00, 0x3e, 0x03, 0x1c, 0x03, 0x3e, 0x03, 0x77,
+ 0x03, 0x63, 0x03, 0x80, 0x07, 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
+ };
+
+ static BCursor MuteCursor = {
+ mute_bitmap,
+ mute_mask,
+ 9,
+ 8,
+ true,
+ };
+
+ BlenderCursor[WM_CURSOR_MUTE] = &MuteCursor;
+ END_CURSOR_BLOCK;
+
/****************** Normal Cross Cursor ************************/
BEGIN_CURSOR_BLOCK;
static char cross_bitmap[] = {
0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x00, 0x00, 0x3e, 0x7c, 0x3e, 0x7c, 0x00, 0x00, 0x80, 0x01,
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
-
};
static char cross_mask[] = {
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 85611a0be93..e0c4ab8eaf3 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -98,7 +98,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
return;
}
- LISTBASE_FOREACH (wmPaintCursor *, pc, &wm->paintcursors) {
+ LISTBASE_FOREACH_MUTABLE (wmPaintCursor *, pc, &wm->paintcursors) {
if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) {
continue;
}
@@ -117,7 +117,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
int x = 0, y = 0;
- wm_get_cursor_position(win, &x, &y);
+ wm_cursor_position_get(win, &x, &y);
pc->draw(C, x, y, pc->customdata);
}
else {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 411ecb1cac8..ed1b53e8e20 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -126,12 +126,12 @@ wmEvent *wm_event_add_ex(wmWindow *win,
*event = *event_to_add;
if (event_to_add_after == NULL) {
- BLI_addtail(&win->queue, event);
+ BLI_addtail(&win->event_queue, event);
}
else {
/* Note: strictly speaking this breaks const-correctness,
* however we're only changing 'next' member. */
- BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event);
+ BLI_insertlinkafter(&win->event_queue, (void *)event_to_add_after, event);
}
return event;
}
@@ -205,7 +205,7 @@ void wm_event_free(wmEvent *event)
static void wm_event_free_last(wmWindow *win)
{
- wmEvent *event = BLI_poptail(&win->queue);
+ wmEvent *event = BLI_poptail(&win->event_queue);
if (event != NULL) {
wm_event_free(event);
}
@@ -214,7 +214,7 @@ static void wm_event_free_last(wmWindow *win)
void wm_event_free_all(wmWindow *win)
{
wmEvent *event;
- while ((event = BLI_pophead(&win->queue))) {
+ while ((event = BLI_pophead(&win->event_queue))) {
wm_event_free(event);
}
}
@@ -232,7 +232,7 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event)
static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference)
{
- LISTBASE_FOREACH (wmNotifier *, note, &wm->queue) {
+ LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) {
if ((note->category | note->data | note->subtype | note->action) == type &&
note->reference == reference) {
return true;
@@ -250,7 +250,7 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ
wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
- BLI_addtail(&wm->queue, note);
+ BLI_addtail(&wm->notifier_queue, note);
note->window = win;
@@ -279,7 +279,7 @@ void WM_main_add_notifier(unsigned int type, void *reference)
wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
- BLI_addtail(&wm->queue, note);
+ BLI_addtail(&wm->notifier_queue, note);
note->category = type & NOTE_CATEGORY;
note->data = type & NOTE_DATA;
@@ -298,7 +298,7 @@ void WM_main_remove_notifier_reference(const void *reference)
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->queue) {
+ LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
if (note->reference == reference) {
/* Don't remove because this causes problems for #wm_event_do_notifiers
* which may be looping on the data (deleting screens). */
@@ -450,7 +450,7 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, win);
- LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->queue) {
+ LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
if (note->category == NC_WM) {
if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
wm->file_saved = 1;
@@ -539,7 +539,7 @@ void wm_event_do_notifiers(bContext *C)
/* The notifiers are sent without context, to keep it clean. */
wmNotifier *note;
- while ((note = BLI_pophead(&wm->queue))) {
+ while ((note = BLI_pophead(&wm->notifier_queue))) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
Scene *scene = WM_window_get_active_scene(win);
bScreen *screen = WM_window_get_active_screen(win);
@@ -577,6 +577,13 @@ void wm_event_do_notifiers(bContext *C)
}
ED_screen_areas_iter (win, screen, area) {
+ if ((note->category == NC_SPACE) && note->reference) {
+ /* Filter out notifiers sent to other spaces. RNA sets the reference to the owning ID
+ * though, the screen, so let notifiers through that reference the entire screen. */
+ if ((note->reference != area->spacedata.first) && (note->reference != screen)) {
+ continue;
+ }
+ }
wmSpaceTypeListenerParams area_params = {
.window = win,
.area = area,
@@ -1319,7 +1326,7 @@ static int wm_operator_invoke(bContext *C,
op->flag |= OP_IS_INVOKE;
}
- /* /initialize setting from previous run. */
+ /* Initialize setting from previous run. */
if (!is_nested_call && use_last_properties) { /* Not called by py script. */
WM_operator_last_properties_init(op);
}
@@ -1646,36 +1653,8 @@ int WM_operator_call_py(bContext *C,
const bool is_undo)
{
int retval = OPERATOR_CANCELLED;
-
-#if 0
- wmOperator *op;
- op = wm_operator_create(wm, ot, properties, reports);
-
- if (op->type->exec) {
- if (is_undo && op->type->flag & OPTYPE_UNDO) {
- wm->op_undo_depth++;
- }
-
- retval = op->type->exec(C, op);
- OPERATOR_RETVAL_CHECK(retval);
-
- if (is_undo && op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
- wm->op_undo_depth--;
- }
- }
- else {
- CLOG_WARN(WM_LOG_OPERATORS,
- "\"%s\" operator has no exec function, Python cannot call it",
- op->type->name);
- }
-
-#endif
-
/* Not especially nice using undo depth here. It's used so Python never
- * triggers undo or stores an operator's last used state.
- *
- * We could have some more obvious way of doing this like passing a flag.
- */
+ * triggers undo or stores an operator's last used state. */
wmWindowManager *wm = CTX_wm_manager(C);
if (!is_undo && wm) {
wm->op_undo_depth++;
@@ -2084,6 +2063,7 @@ static int wm_handler_operator_call(bContext *C,
else if (ot->modal) {
/* We set context to where modal handler came from. */
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -2101,22 +2081,21 @@ static int wm_handler_operator_call(bContext *C,
retval = ot->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
- /* When this is _not_ the case the modal modifier may have loaded
- * a new blend file (demo mode does this), so we have to assume
- * the event, operator etc have all been freed. - campbell */
- if (CTX_wm_manager(C) == wm) {
+ if (ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
+ wm->op_undo_depth--;
+ }
- wm_event_modalkeymap_end(event, &event_backup);
+ /* When the window changes the the modal modifier may have loaded a new blend file
+ * (the `system_demo_mode` add-on does this), so we have to assume the event,
+ * operator, area, region etc have all been freed. */
+ if ((CTX_wm_window(C) == win)) {
- if (ot->flag & OPTYPE_UNDO) {
- wm->op_undo_depth--;
- }
+ wm_event_modalkeymap_end(event, &event_backup);
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
wm_operator_reports(C, op, retval, false);
if (op->type->modalkeymap) {
- wmWindow *win = CTX_wm_window(C);
WM_window_status_area_tag_redraw(win);
}
}
@@ -2343,7 +2322,7 @@ static int wm_handler_fileselect_do(bContext *C,
wm_window_make_drawable(wm, ctx_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (UI_BLOCK_MOVEMOUSE_QUIT). */
- wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
+ wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
wm->winactive = ctx_win; /* Reports use this... */
if (handler->context.win == win) {
handler->context.win = NULL;
@@ -2951,17 +2930,16 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
int action = wm_handlers_do_intern(C, event, handlers);
- /* Fileread case. */
- if (CTX_wm_window(C) == NULL) {
+ /* Will be NULL in the file read case. */
+ wmWindow *win = CTX_wm_window(C);
+ if (win == NULL) {
return action;
}
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
-
/* Test for CLICK_DRAG events. */
if (wm_action_not_handled(action)) {
- if (event->check_drag) {
- wmWindow *win = CTX_wm_window(C);
+ if (win->event_queue_check_drag) {
if (WM_event_drag_test(event, &event->prevclickx)) {
int x = event->x;
int y = event->y;
@@ -2982,16 +2960,16 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
event->x = x;
event->y = y;
- win->eventstate->check_click = false;
- win->eventstate->check_drag = false;
+ win->event_queue_check_click = false;
+ if (!wm_action_not_handled(action)) {
+ /* Only disable when handled as other handlers may use this drag event. */
+ win->event_queue_check_drag = false;
+ }
}
}
}
else {
- wmWindow *win = CTX_wm_window(C);
- if (win) {
- win->eventstate->check_drag = false;
- }
+ win->event_queue_check_drag = false;
}
}
else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) {
@@ -2999,29 +2977,27 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
/* Test for CLICK events. */
if (wm_action_not_handled(action)) {
- wmWindow *win = CTX_wm_window(C);
-
/* eventstate stores if previous event was a KM_PRESS, in case that
* wasn't handled, the KM_RELEASE will become a KM_CLICK */
- if (win != NULL) {
- if (event->val == KM_PRESS) {
- win->eventstate->check_click = true;
- win->eventstate->check_drag = true;
- }
- else if (event->val == KM_RELEASE) {
- win->eventstate->check_drag = false;
+ if (event->val == KM_PRESS) {
+ if (event->is_repeat == false) {
+ win->event_queue_check_click = true;
+ win->event_queue_check_drag = true;
}
}
+ else if (event->val == KM_RELEASE) {
+ win->event_queue_check_drag = false;
+ }
- if (win && event->prevtype == event->type) {
+ if (event->prevtype == event->type) {
if (event->val == KM_RELEASE) {
if (event->prevval == KM_PRESS) {
- if (win->eventstate->check_click == true) {
+ if (win->event_queue_check_click == true) {
if (WM_event_drag_test(event, &event->prevclickx)) {
- win->eventstate->check_click = 0;
- win->eventstate->check_drag = 0;
+ win->event_queue_check_click = false;
+ win->event_queue_check_drag = false;
}
else {
/* Position is where the actual click happens, for more
@@ -3057,11 +3033,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
}
}
else {
- wmWindow *win = CTX_wm_window(C);
- if (win) {
- win->eventstate->check_click = 0;
- win->eventstate->check_drag = 0;
- }
+ win->event_queue_check_click = false;
+ win->event_queue_check_drag = false;
}
}
else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) {
@@ -3071,11 +3044,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
/* pass */
}
else {
- wmWindow *win = CTX_wm_window(C);
- if (win) {
- if (ISKEYMODIFIER(event->prevtype)) {
- win->eventstate->check_click = 0;
- }
+ if (ISKEYMODIFIER(event->prevtype)) {
+ win->event_queue_check_click = false;
}
}
}
@@ -3199,7 +3169,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
event->type = EVT_DROP;
- /* Vreate customdata, first free existing. */
+ /* Create customdata, first free existing. */
if (event->customdata) {
if (event->customdatafree) {
MEM_freeN(event->customdata);
@@ -3210,7 +3180,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
event->customdata = &wm->drags;
event->customdatafree = 1;
- /* Vlear drop icon. */
+ /* Clear drop icon. */
screen->do_draw_drag = true;
/* restore cursor (disabled, see wm_dragdrop.c) */
@@ -3221,9 +3191,9 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
/* Filter out all events of the pie that spawned the last pie unless it's a release event. */
static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
{
- if (win->lock_pie_event && win->lock_pie_event == event->type) {
+ if (win->pie_event_type_lock && win->pie_event_type_lock == event->type) {
if (event->val == KM_RELEASE) {
- win->lock_pie_event = EVENT_NONE;
+ win->pie_event_type_lock = EVENT_NONE;
return false;
}
return true;
@@ -3234,7 +3204,7 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
/**
* Account for the special case when events are being handled and a file is loaded.
* In this case event handling exits early, however when "Load UI" is disabled
- * the even will still be in #wmWindow.queue.
+ * the even will still be in #wmWindow.event_queue.
*
* Without this it's possible to continuously handle the same event, see: T76484.
*/
@@ -3242,7 +3212,7 @@ static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
{
LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
- if (BLI_remlink_safe(&win->queue, event)) {
+ if (BLI_remlink_safe(&win->event_queue, event)) {
wm_event_free(event);
return;
}
@@ -3331,7 +3301,7 @@ void wm_event_do_handlers(bContext *C)
}
wmEvent *event;
- while ((event = win->queue.first)) {
+ while ((event = win->event_queue.first)) {
int action = WM_HANDLER_CONTINUE;
/* Active screen might change during handlers, update pointer. */
@@ -3348,7 +3318,7 @@ void wm_event_do_handlers(bContext *C)
if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed");
}
- BLI_remlink(&win->queue, event);
+ BLI_remlink(&win->event_queue, event);
wm_event_free(event);
continue;
}
@@ -3497,7 +3467,7 @@ void wm_event_do_handlers(bContext *C)
* press in tool keymap can override click in editor keymap.*/
if (ISMOUSE_BUTTON(event->type) && event->val == KM_PRESS &&
!wm_action_not_handled(action)) {
- win->eventstate->check_click = false;
+ win->event_queue_check_click = false;
}
/* Update previous mouse position for following events to use. */
@@ -3505,11 +3475,11 @@ void wm_event_do_handlers(bContext *C)
win->eventstate->prevy = event->y;
/* Unlink and free here, blender-quit then frees all. */
- BLI_remlink(&win->queue, event);
+ BLI_remlink(&win->event_queue, event);
wm_event_free(event);
}
- /* Only add mousemove when queue was read entirely. */
+ /* Only add mouse-move when the event queue was read entirely. */
if (win->addmousemove && win->eventstate) {
wmEvent tevent = *(win->eventstate);
// printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
@@ -4350,11 +4320,11 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
}
}
- wmWindow *owin;
- if (WM_window_find_under_cursor(wm, win, win, mval, &owin, mval)) {
+ wmWindow *win_other;
+ if (WM_window_find_under_cursor(wm, win, win, mval, &win_other, mval)) {
event->x = mval[0];
event->y = mval[1];
- return owin;
+ return win_other;
}
}
return NULL;
@@ -4395,7 +4365,7 @@ static void wm_event_prev_click_set(wmEvent *event, wmEvent *event_state)
static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
{
- wmEvent *event_last = win->queue.last;
+ wmEvent *event_last = win->event_queue.last;
/* Some painting operators want accurate mouse events, they can
* handle in between mouse move moves, others can happily ignore
@@ -4417,7 +4387,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
{
/* Ignore in between trackpad events for performance, we only need high accuracy
* for painting with mouse moves, for navigation using the accumulated value is ok. */
- wmEvent *event_last = win->queue.last;
+ wmEvent *event_last = win->event_queue.last;
if (event_last && event_last->type == event->type) {
deltax += event_last->x - event_last->prevx;
deltay += event_last->y - event_last->prevy;
@@ -4434,7 +4404,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
}
/**
- * Windows store own event queues #wmWindow.queue (no #bContext here).
+ * Windows store own event queues #wmWindow.event_queue (no #bContext here).
*/
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
{
@@ -4443,19 +4413,19 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
/**
- * Having both, \a event and \a evt, can be highly confusing to work with,
+ * Having both, \a event and \a event_state, can be highly confusing to work with,
* but is necessary for our current event system, so let's clear things up a bit:
*
* - Data added to event only will be handled immediately,
* but will not be copied to the next event.
- * - Data added to \a evt only stays,
+ * - Data added to \a event_state only stays,
* but is handled with the next event -> execution delay.
- * - Data added to event and \a evt stays and is handled immediately.
+ * - Data added to event and \a event_state stays and is handled immediately.
*/
- wmEvent event, *evt = win->eventstate;
+ wmEvent event, *event_state = win->eventstate;
/* Initialize and copy state (only mouse x y and modifiers). */
- event = *evt;
+ event = *event_state;
event.is_repeat = false;
/**
@@ -4473,17 +4443,17 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Ensure the event state is correct, any deviation from this may cause bugs. */
#ifndef NDEBUG
- if ((evt->type || evt->val) && /* Ignore cleared event state. */
- !(ISMOUSE_BUTTON(evt->type) || ISKEYBOARD(evt->type))) {
+ if ((event_state->type || event_state->val) && /* Ignore cleared event state. */
+ !(ISMOUSE_BUTTON(event_state->type) || ISKEYBOARD(event_state->type))) {
CLOG_WARN(WM_LOG_HANDLERS,
"Non-keyboard/mouse button found in 'win->eventstate->type = %d'",
- evt->type);
+ event_state->type);
}
- if ((evt->prevtype || evt->prevval) && /* Ignore cleared event state. */
- !(ISMOUSE_BUTTON(evt->prevtype) || ISKEYBOARD(evt->prevtype))) {
+ if ((event_state->prevtype || event_state->prevval) && /* Ignore cleared event state. */
+ !(ISMOUSE_BUTTON(event_state->prevtype) || ISKEYBOARD(event_state->prevtype))) {
CLOG_WARN(WM_LOG_HANDLERS,
"Non-keyboard/mouse button found in 'win->eventstate->prevtype = %d'",
- evt->prevtype);
+ event_state->prevtype);
}
#endif
@@ -4499,28 +4469,26 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.type = MOUSEMOVE;
{
wmEvent *event_new = wm_event_add_mousemove(win, &event);
- copy_v2_v2_int(&evt->x, &event_new->x);
- evt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
+ copy_v2_v2_int(&event_state->x, &event_new->x);
+ event_state->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
/* Also add to other window if event is there, this makes overdraws disappear nicely. */
/* It remaps mousecoord to other window in event. */
- wmWindow *owin = wm_event_cursor_other_windows(wm, win, &event);
- if (owin) {
- wmEvent oevent, *oevt = owin->eventstate;
-
- oevent = *oevt;
+ wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
+ if (win_other) {
+ wmEvent event_other = *win_other->eventstate;
/* See comment for this operation on `event` for details. */
- oevent.prevtype = oevent.type;
- oevent.prevval = oevent.val;
+ event_other.prevtype = event_other.type;
+ event_other.prevval = event_other.val;
- copy_v2_v2_int(&oevent.x, &event.x);
- oevent.type = MOUSEMOVE;
+ copy_v2_v2_int(&event_other.x, &event.x);
+ event_other.type = MOUSEMOVE;
{
- wmEvent *event_new = wm_event_add_mousemove(owin, &oevent);
- copy_v2_v2_int(&oevt->x, &event_new->x);
- oevt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
+ wmEvent *event_new = wm_event_add_mousemove(win_other, &event_other);
+ copy_v2_v2_int(&win_other->eventstate->x, &event_new->x);
+ win_other->eventstate->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
}
@@ -4546,8 +4514,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
break;
}
- event.x = evt->x = pd->x;
- event.y = evt->y = pd->y;
+ event.x = event_state->x = pd->x;
+ event.y = event_state->y = pd->y;
event.val = KM_NOTHING;
/* The direction is inverted from the device due to system preferences. */
@@ -4590,11 +4558,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
wm_eventemulation(&event, false);
- wm_event_prev_values_set(&event, evt);
+ wm_event_prev_values_set(&event, event_state);
/* Copy to event state. */
- evt->val = event.val;
- evt->type = event.type;
+ event_state->val = event.val;
+ event_state->type = event.type;
/* Double click test. */
if (wm_event_is_double_click(&event)) {
@@ -4602,25 +4570,25 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.val = KM_DBL_CLICK;
}
if (event.val == KM_PRESS) {
- wm_event_prev_click_set(&event, evt);
+ wm_event_prev_click_set(&event, event_state);
}
/* Add to other window if event is there (not to both!). */
- wmWindow *owin = wm_event_cursor_other_windows(wm, win, &event);
- if (owin) {
- wmEvent oevent = *(owin->eventstate);
+ wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
+ if (win_other) {
+ wmEvent event_other = *win_other->eventstate;
/* See comment for this operation on `event` for details. */
- oevent.prevtype = oevent.type;
- oevent.prevval = oevent.val;
+ event_other.prevtype = event_other.type;
+ event_other.prevval = event_other.val;
- copy_v2_v2_int(&oevent.x, &event.x);
+ copy_v2_v2_int(&event_other.x, &event.x);
- oevent.type = event.type;
- oevent.val = event.val;
- oevent.tablet = event.tablet;
+ event_other.type = event.type;
+ event_other.val = event.val;
+ event_other.tablet = event.tablet;
- wm_event_add(owin, &oevent);
+ wm_event_add(win_other, &event_other);
}
else {
wm_event_add(win, &event);
@@ -4641,12 +4609,12 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE;
wm_eventemulation(&event, false);
- wm_event_prev_values_set(&event, evt);
+ wm_event_prev_values_set(&event, event_state);
/* Copy to event state. */
- evt->val = event.val;
- evt->type = event.type;
- evt->is_repeat = event.is_repeat;
+ event_state->val = event.val;
+ event_state->type = event.type;
+ event_state->is_repeat = event.is_repeat;
/* Exclude arrow keys, esc, etc from text input. */
if (type == GHOST_kEventKeyUp) {
@@ -4682,57 +4650,57 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY:
if (event.val == KM_PRESS) {
- if (evt->ctrl || evt->alt || evt->oskey) {
+ if (event_state->ctrl || event_state->alt || event_state->oskey) {
keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
}
else {
keymodifier = KM_MOD_FIRST;
}
}
- event.shift = evt->shift = keymodifier;
+ event.shift = event_state->shift = keymodifier;
break;
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY:
if (event.val == KM_PRESS) {
- if (evt->shift || evt->alt || evt->oskey) {
+ if (event_state->shift || event_state->alt || event_state->oskey) {
keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
}
else {
keymodifier = KM_MOD_FIRST;
}
}
- event.ctrl = evt->ctrl = keymodifier;
+ event.ctrl = event_state->ctrl = keymodifier;
break;
case EVT_LEFTALTKEY:
case EVT_RIGHTALTKEY:
if (event.val == KM_PRESS) {
- if (evt->ctrl || evt->shift || evt->oskey) {
+ if (event_state->ctrl || event_state->shift || event_state->oskey) {
keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
}
else {
keymodifier = KM_MOD_FIRST;
}
}
- event.alt = evt->alt = keymodifier;
+ event.alt = event_state->alt = keymodifier;
break;
case EVT_OSKEY:
if (event.val == KM_PRESS) {
- if (evt->ctrl || evt->alt || evt->shift) {
+ if (event_state->ctrl || event_state->alt || event_state->shift) {
keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
}
else {
keymodifier = KM_MOD_FIRST;
}
}
- event.oskey = evt->oskey = keymodifier;
+ event.oskey = event_state->oskey = keymodifier;
break;
default:
if (event.val == KM_PRESS && event.keymodifier == 0) {
/* Only set in eventstate, for next event. */
- evt->keymodifier = event.type;
+ event_state->keymodifier = event.type;
}
else if (event.val == KM_RELEASE && event.keymodifier == event.type) {
- event.keymodifier = evt->keymodifier = 0;
+ event.keymodifier = event_state->keymodifier = 0;
}
break;
}
@@ -4755,7 +4723,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
* Since it's impossible to map a key modifier to an unknown key,
* it shouldn't harm to clear it. */
if (event.keymodifier == EVT_UNKNOWNKEY) {
- evt->keymodifier = event.keymodifier = 0;
+ event_state->keymodifier = event.keymodifier = 0;
}
/* If test_break set, it catches this. Do not set with modifier presses.
@@ -4770,7 +4738,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
if (event.val == KM_PRESS) {
/* Don't reset timer & location when holding the key generates repeat events. */
if (event.is_repeat == false) {
- wm_event_prev_click_set(&event, evt);
+ wm_event_prev_click_set(&event, event_state);
}
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index d2d080a9a68..a9b30f91bee 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -81,6 +81,7 @@
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -138,6 +139,8 @@
#include "wm_files.h"
#include "wm_window.h"
+#include "CLG_log.h"
+
static RecentFile *wm_file_history_find(const char *filepath);
static void wm_history_file_free(RecentFile *recent);
static void wm_history_files_free(void);
@@ -146,6 +149,8 @@ static void wm_history_file_write(void);
static void wm_test_autorun_revert_action_exec(bContext *C);
+static CLG_LogRef LOG = {"wm.files"};
+
/* -------------------------------------------------------------------- */
/** \name Misc Utility Functions
* \{ */
@@ -296,6 +301,36 @@ static void wm_window_match_replace_by_file_wm(bContext *C,
{
wmWindowManager *oldwm = current_wm_list->first;
wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
+
+ /* Support window-manager ID references being held between file load operations by keeping
+ * #Main.wm.first memory address in-place, while swapping all of it's contents.
+ *
+ * This is needed so items such as key-maps can be held by an add-on,
+ * without it pointing to invalid memory, see: T86431 */
+ {
+ /* Referencing the window-manager pointer from elsewhere in the file is highly unlikely
+ * however it's possible with ID-properties & animation-drivers.
+ * At some point we could check on disallowing this since it doesn't seem practical. */
+ Main *bmain = G_MAIN;
+ BLI_assert(bmain->relations == NULL);
+ BKE_libblock_remap(bmain, wm, oldwm, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_USER_CLEAR);
+
+ /* Maintain the undo-depth between file loads. Useful so Python can perform
+ * nested operator calls that exit with the proper undo-depth. */
+ wm->op_undo_depth = oldwm->op_undo_depth;
+
+ /* Simple pointer swapping step. */
+ BLI_remlink(current_wm_list, oldwm);
+ BLI_remlink(readfile_wm_list, wm);
+ SWAP(wmWindowManager, *oldwm, *wm);
+ SWAP(wmWindowManager *, oldwm, wm);
+ BLI_addhead(current_wm_list, oldwm);
+ BLI_addhead(readfile_wm_list, wm);
+
+ /* Don't leave the old pointer in the context. */
+ CTX_wm_manager_set(C, wm);
+ }
+
bool has_match = false;
/* this code could move to setup_appdata */
@@ -711,9 +746,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* so we can get the error message */
errno = 0;
- WM_cursor_wait(1);
-
- wm_file_read_pre(C, use_data, use_userdef);
+ WM_cursor_wait(true);
/* first try to append data from exotic file formats... */
/* it throws error box when file doesn't exist and returns -1 */
@@ -722,58 +755,60 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* we didn't succeed, now try to read Blender file */
if (retval == BKE_READ_EXOTIC_OK_BLEND) {
- const int G_f_orig = G.f;
- ListBase wmbase;
-
- /* put aside screens to match with persistent windows later */
- /* also exit screens and editors */
- wm_window_match_init(C, &wmbase);
+ const struct BlendFileReadParams params = {
+ .is_startup = false,
+ /* Loading preferences when the user intended to load a regular file is a security
+ * risk, because the excluded path list is also loaded. Further it's just confusing
+ * if a user loads a file and various preferences change. */
+ .skip_flags = BLO_READ_SKIP_USERDEF,
+ };
+
+ struct BlendFileData *bfd = BKE_blendfile_read(filepath, &params, reports);
+ if (bfd != NULL) {
+ wm_file_read_pre(C, use_data, use_userdef);
+
+ /* Put aside screens to match with persistent windows later,
+ * also exit screens and editors. */
+ ListBase wmbase;
+ wm_window_match_init(C, &wmbase);
+
+ /* This flag is initialized by the operator but overwritten on read.
+ * need to re-enable it here else drivers + registered scripts wont work. */
+ const int G_f_orig = G.f;
+
+ BKE_blendfile_read_setup(C, bfd, &params, reports);
+
+ if (G.f != G_f_orig) {
+ const int flags_keep = G_FLAG_ALL_RUNTIME;
+ G.f &= G_FLAG_ALL_READFILE;
+ G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep);
+ }
- /* confusing this global... */
- G.relbase_valid = 1;
- success = BKE_blendfile_read(
- C,
- filepath,
- /* Loading preferences when the user intended to load a regular file is a security risk,
- * because the excluded path list is also loaded.
- * Further it's just confusing if a user loads a file and various preferences change. */
- &(const struct BlendFileReadParams){
- .is_startup = false,
- .skip_flags = BLO_READ_SKIP_USERDEF,
- },
- reports);
-
- /* BKE_file_read sets new Main into context. */
- Main *bmain = CTX_data_main(C);
-
- /* when loading startup.blend's, we can be left with a blank path */
- if (BKE_main_blendfile_path(bmain)[0] != '\0') {
- G.save_over = 1;
- }
- else {
- G.save_over = 0;
- G.relbase_valid = 0;
- }
+ /* #BKE_blendfile_read_result_setup sets new Main into context. */
+ Main *bmain = CTX_data_main(C);
- /* this flag is initialized by the operator but overwritten on read.
- * need to re-enable it here else drivers + registered scripts wont work. */
- if (G.f != G_f_orig) {
- const int flags_keep = G_FLAG_ALL_RUNTIME;
- G.f &= G_FLAG_ALL_READFILE;
- G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep);
- }
+ /* When recovering a session from an unsaved file, this can have a blank path. */
+ if (BKE_main_blendfile_path(bmain)[0] != '\0') {
+ G.save_over = 1;
+ G.relbase_valid = 1;
+ }
+ else {
+ G.save_over = 0;
+ G.relbase_valid = 0;
+ }
- /* match the read WM with current WM */
- wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
- WM_check(C); /* opens window(s), checks keymaps */
+ /* match the read WM with current WM */
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
+ WM_check(C); /* opens window(s), checks keymaps */
- if (success) {
if (do_history_file_update) {
wm_history_file_update();
}
- }
- wm_file_read_post(C, false, false, use_data, use_userdef, false);
+ wm_file_read_post(C, false, false, use_data, use_userdef, false);
+
+ success = true;
+ }
}
#if 0
else if (retval == BKE_READ_EXOTIC_OK_OTHER) {
@@ -809,7 +844,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
return success;
}
@@ -950,6 +985,9 @@ void wm_homefile_read(bContext *C,
#endif /* WITH_PYTHON */
}
+ /* For regular file loading this only runs after the file is successfully read.
+ * In the case of the startup file, the in-memory startup file is used as a fallback
+ * so we know this will work if all else fails. */
wm_file_read_pre(C, use_data, use_userdef);
if (use_data) {
@@ -1041,15 +1079,17 @@ void wm_homefile_read(bContext *C,
if (!use_factory_settings || (filepath_startup[0] != '\0')) {
if (BLI_access(filepath_startup, R_OK) == 0) {
- success = BKE_blendfile_read_ex(C,
- filepath_startup,
- &(const struct BlendFileReadParams){
- .is_startup = true,
- .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF,
- },
- NULL,
- update_defaults && use_data,
- app_template);
+ const struct BlendFileReadParams params = {
+ .is_startup = true,
+ .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF,
+ };
+
+ struct BlendFileData *bfd = BKE_blendfile_read(filepath_startup, &params, NULL);
+ if (bfd != NULL) {
+ BKE_blendfile_read_setup_ex(
+ C, bfd, &params, NULL, update_defaults && use_data, app_template);
+ success = true;
+ }
}
if (success) {
is_factory_startup = filepath_startup_is_factory;
@@ -1070,16 +1110,16 @@ void wm_homefile_read(bContext *C,
}
if (success == false) {
- success = BKE_blendfile_read_from_memory_ex(C,
- datatoc_startup_blend,
- datatoc_startup_blend_size,
- &(const struct BlendFileReadParams){
- .is_startup = true,
- .skip_flags = skip_flags,
- },
- NULL,
- true,
- NULL);
+ const struct BlendFileReadParams params = {
+ .is_startup = true,
+ .skip_flags = skip_flags,
+ };
+ struct BlendFileData *bfd = BKE_blendfile_read_from_memory(
+ datatoc_startup_blend, datatoc_startup_blend_size, &params, NULL);
+ if (bfd != NULL) {
+ BKE_blendfile_read_setup_ex(C, bfd, &params, NULL, true, NULL);
+ success = true;
+ }
if (use_data && BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
@@ -1404,7 +1444,7 @@ static ImBuf *blend_file_thumb(const bContext *C,
}
else {
/* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
- fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out);
+ CLOG_WARN(&LOG, "failed to create thumbnail: %s", err_out);
thumb = NULL;
}
@@ -1498,7 +1538,7 @@ static bool wm_file_write(bContext *C,
}
/* don't forget not to return without! */
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
ED_editors_flush_edits(bmain);
@@ -1560,7 +1600,7 @@ static bool wm_file_write(bContext *C,
MEM_freeN(thumb);
}
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
return ok;
}
@@ -1571,7 +1611,7 @@ static bool wm_file_write(bContext *C,
/** \name Auto-Save API
* \{ */
-void wm_autosave_location(char *filepath)
+static void wm_autosave_location(char *filepath)
{
const int pid = abs(getpid());
char path[1024];
@@ -1607,20 +1647,67 @@ void wm_autosave_location(char *filepath)
BLI_join_dirfile(filepath, FILE_MAX, BKE_tempdir_base(), path);
}
-void WM_autosave_init(wmWindowManager *wm)
+static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
{
- wm_autosave_timer_ended(wm);
+ char filepath[FILE_MAX];
+
+ wm_autosave_location(filepath);
+
+ /* Fast save of last undo-buffer, now with UI. */
+ const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0;
+ MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL;
+ if (memfile != NULL) {
+ BLO_memfile_write_file(memfile, filepath);
+ }
+ else {
+ if (use_memfile) {
+ /* This is very unlikely, alert developers of this unexpected case. */
+ CLOG_WARN(&LOG, "undo-data not found for writing, fallback to regular file write!");
+ }
+
+ /* Save as regular blend file with recovery information. */
+ const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE;
+
+ ED_editors_flush_edits(bmain);
+
+ /* Error reporting into console. */
+ BLO_write_file(bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
+ }
+}
+
+static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep)
+{
+ wm_autosave_timer_end(wm);
if (U.flag & USER_AUTOSAVE) {
- wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0);
+ wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, timestep);
}
}
-void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
+void wm_autosave_timer_begin(wmWindowManager *wm)
{
- char filepath[FILE_MAX];
+ wm_autosave_timer_begin_ex(wm, U.savetime * 60.0);
+}
+
+void wm_autosave_timer_end(wmWindowManager *wm)
+{
+ if (wm->autosavetimer) {
+ WM_event_remove_timer(wm, NULL, wm->autosavetimer);
+ wm->autosavetimer = NULL;
+ }
+}
- WM_event_remove_timer(wm, NULL, wm->autosavetimer);
+void WM_autosave_init(wmWindowManager *wm)
+{
+ wm_autosave_timer_begin(wm);
+}
+
+/**
+ * Run the auto-save timer action.
+ */
+void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
+{
+ wm_autosave_timer_end(wm);
/* If a modal operator is running, don't autosave because we might not be in
* a valid state to save. But try again in 10ms. */
@@ -1629,41 +1716,17 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
if (handler->op) {
- wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 0.01);
+ wm_autosave_timer_begin_ex(wm, 0.01);
return;
}
}
}
}
- wm_autosave_location(filepath);
+ wm_autosave_write(bmain, wm);
- if (U.uiflag & USER_GLOBALUNDO) {
- /* fast save of last undobuffer, now with UI */
- struct MemFile *memfile = ED_undosys_stack_memfile_get_active(wm->undo_stack);
- if (memfile) {
- BLO_memfile_write_file(memfile, filepath);
- }
- }
- else {
- /* Save as regular blend file. */
- const int fileflags = G.fileflags & ~G_FILE_COMPRESS;
-
- ED_editors_flush_edits(bmain);
-
- /* Error reporting into console. */
- BLO_write_file(bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
- }
- /* do timer after file write, just in case file write takes a long time */
- wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0);
-}
-
-void wm_autosave_timer_ended(wmWindowManager *wm)
-{
- if (wm->autosavetimer) {
- WM_event_remove_timer(wm, NULL, wm->autosavetimer);
- wm->autosavetimer = NULL;
- }
+ /* Restart the timer after file write, just in case file write takes a long time. */
+ wm_autosave_timer_begin(wm);
}
void wm_autosave_delete(void)
@@ -1686,14 +1749,6 @@ void wm_autosave_delete(void)
}
}
-void wm_autosave_read(bContext *C, ReportList *reports)
-{
- char filename[FILE_MAX];
-
- wm_autosave_location(filename);
- WM_file_read(C, filename, reports);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1776,7 +1831,12 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
filepath,
fileflags,
&(const struct BlendFileWriteParams){
- .remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE,
+ /* Make all paths absolute when saving the startup file.
+ * On load the `G.relbase_valid` will be false so the paths
+ * wont have a base for resolving the relative paths. */
+ .remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
+ /* Don't apply any path changes to the current blend file. */
+ .use_save_as_copy = true,
},
op->reports) == 0) {
printf("fail\n");
@@ -2554,9 +2614,9 @@ bool WM_recover_last_session(bContext *C, ReportList *reports)
{
char filepath[FILE_MAX];
BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
- G.fileflags |= G_FILE_RECOVER;
+ G.fileflags |= G_FILE_RECOVER_READ;
const bool success = wm_file_read_opwrap(C, filepath, reports);
- G.fileflags &= ~G_FILE_RECOVER;
+ G.fileflags &= ~G_FILE_RECOVER_READ;
return success;
}
@@ -2613,11 +2673,11 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
wm_open_init_use_scripts(op, true);
SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC);
- G.fileflags |= G_FILE_RECOVER;
+ G.fileflags |= G_FILE_RECOVER_READ;
success = wm_file_read_opwrap(C, filepath, op->reports);
- G.fileflags &= ~G_FILE_RECOVER;
+ G.fileflags &= ~G_FILE_RECOVER_READ;
if (success) {
if (!G.background) {
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index d4495821672..bf7cf81f0a9 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -229,6 +229,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
Library *lib;
const int flag = lapp_data->flag;
+ const int id_tag_extra = 0;
LinkNode *liblink, *itemlink;
int lib_idx, item_idx;
@@ -255,7 +256,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
/* here appending/linking starts */
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init_with_context(
- &liblink_params, bmain, flag, scene, view_layer, v3d);
+ &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
lib = mainl->curlib;
@@ -804,7 +805,7 @@ static void lib_relocate_do(Main *bmain,
ReportList *reports,
const bool do_reload)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[INDEX_ID_MAX];
int lba_idx;
LinkNode *itemlink;
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index cf45d380c48..1cddc019ff8 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -605,7 +605,7 @@ void WM_jobs_kill(wmWindowManager *wm,
}
/* kill job entirely, also removes timer itself */
-void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt)
+void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
if (wm_job->wt == wt) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 6cc9a4c9b64..38d06ea83d3 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -1773,10 +1773,6 @@ void WM_keyconfig_update(wmWindowManager *wm)
{
bool compat_update = false;
- if (G.background) {
- return;
- }
-
if (wm_keymap_update_flag == 0) {
return;
}
@@ -1805,72 +1801,71 @@ void WM_keyconfig_update(wmWindowManager *wm)
wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_OPERATORTYPE;
}
- if (wm_keymap_update_flag == 0) {
- return;
- }
-
- /* update operator properties for non-modal user keymaps */
- LISTBASE_FOREACH (wmKeyMap *, km, &U.user_keymaps) {
- if ((km->flag & KEYMAP_MODAL) == 0) {
- LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
- if (kmdi->add_item) {
- wm_keymap_item_properties_set(kmdi->add_item);
+ if (wm_keymap_update_flag & WM_KEYMAP_UPDATE_RECONFIGURE) {
+ /* update operator properties for non-modal user keymaps */
+ LISTBASE_FOREACH (wmKeyMap *, km, &U.user_keymaps) {
+ if ((km->flag & KEYMAP_MODAL) == 0) {
+ LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
+ if (kmdi->add_item) {
+ wm_keymap_item_properties_set(kmdi->add_item);
+ }
+ if (kmdi->remove_item) {
+ wm_keymap_item_properties_set(kmdi->remove_item);
+ }
}
- if (kmdi->remove_item) {
- wm_keymap_item_properties_set(kmdi->remove_item);
+
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
+ wm_keymap_item_properties_set(kmi);
}
}
+ }
- LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
- wm_keymap_item_properties_set(kmi);
+ /* update U.user_keymaps with user key configuration changes */
+ LISTBASE_FOREACH (wmKeyMap *, km, &wm->userconf->keymaps) {
+ /* only diff if the user keymap was modified */
+ if (wm_keymap_test_and_clear_update(km)) {
+ /* find keymaps */
+ wmKeyMap *defaultmap = wm_keymap_preset(wm, km);
+ wmKeyMap *addonmap = WM_keymap_list_find(
+ &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
+
+ /* diff */
+ if (defaultmap) {
+ wm_keymap_diff_update(&U.user_keymaps, defaultmap, addonmap, km);
+ }
}
}
- }
- /* update U.user_keymaps with user key configuration changes */
- LISTBASE_FOREACH (wmKeyMap *, km, &wm->userconf->keymaps) {
- /* only diff if the user keymap was modified */
- if (wm_keymap_test_and_clear_update(km)) {
+ /* create user key configuration from preset + addon + user preferences */
+ LISTBASE_FOREACH (wmKeyMap *, km, &wm->defaultconf->keymaps) {
/* find keymaps */
wmKeyMap *defaultmap = wm_keymap_preset(wm, km);
wmKeyMap *addonmap = WM_keymap_list_find(
&wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
+ wmKeyMap *usermap = WM_keymap_list_find(
+ &U.user_keymaps, km->idname, km->spaceid, km->regionid);
- /* diff */
- if (defaultmap) {
- wm_keymap_diff_update(&U.user_keymaps, defaultmap, addonmap, km);
- }
- }
- }
-
- /* create user key configuration from preset + addon + user preferences */
- LISTBASE_FOREACH (wmKeyMap *, km, &wm->defaultconf->keymaps) {
- /* find keymaps */
- wmKeyMap *defaultmap = wm_keymap_preset(wm, km);
- wmKeyMap *addonmap = WM_keymap_list_find(
- &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
- wmKeyMap *usermap = WM_keymap_list_find(
- &U.user_keymaps, km->idname, km->spaceid, km->regionid);
+ /* For now only the default map defines modal key-maps,
+ * if we support modal keymaps for 'addonmap', these will need to be enabled too. */
+ wm_user_modal_keymap_set_items(wm, defaultmap);
- /* For now only the default map defines modal key-maps,
- * if we support modal keymaps for 'addonmap', these will need to be enabled too. */
- wm_user_modal_keymap_set_items(wm, defaultmap);
+ /* add */
+ wmKeyMap *kmn = wm_keymap_patch_update(
+ &wm->userconf->keymaps, defaultmap, addonmap, usermap);
- /* add */
- wmKeyMap *kmn = wm_keymap_patch_update(&wm->userconf->keymaps, defaultmap, addonmap, usermap);
+ if (kmn) {
+ kmn->modal_items = km->modal_items;
+ kmn->poll = km->poll;
+ kmn->poll_modal_item = km->poll_modal_item;
+ }
- if (kmn) {
- kmn->modal_items = km->modal_items;
- kmn->poll = km->poll;
- kmn->poll_modal_item = km->poll_modal_item;
+ /* in case of old non-diff keymaps, force extra update to create diffs */
+ compat_update = compat_update || (usermap && !(usermap->flag & KEYMAP_DIFF));
}
- /* in case of old non-diff keymaps, force extra update to create diffs */
- compat_update = compat_update || (usermap && !(usermap->flag & KEYMAP_DIFF));
+ wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_RECONFIGURE;
}
- wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_RECONFIGURE;
-
BLI_assert(wm_keymap_update_flag == 0);
if (compat_update) {
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index aeab1ee6fca..ba236988c1d 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -291,7 +291,7 @@ void WM_operator_properties_select_random(wmOperatorType *ot)
1.0f,
"Ratio",
"Portion of items to select randomly",
- 0.f,
+ 0.0f,
1.0f);
RNA_def_int(ot->srna,
"seed",
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index fa34c561147..660e502a3d7 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3234,7 +3234,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
*/
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- WM_cursor_wait(1);
+ WM_cursor_wait(true);
double time_start = PIL_check_seconds_timer();
@@ -3257,7 +3257,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
RNA_enum_description(redraw_timer_type_items, type, &infostr);
- WM_cursor_wait(0);
+ WM_cursor_wait(false);
BKE_reportf(op->reports,
RPT_WARNING,
diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c
index 65e1cd45e02..45618e9d6d3 100644
--- a/source/blender/windowmanager/intern/wm_platform_support.c
+++ b/source/blender/windowmanager/intern/wm_platform_support.c
@@ -43,7 +43,9 @@
#define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024
-/* Check if user has already approved the given platform_support_key. */
+/**
+ * Check if user has already approved the given `platform_support_key`.
+ */
static bool wm_platform_support_check_approval(const char *platform_support_key, bool update)
{
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
@@ -120,11 +122,11 @@ bool WM_platform_support_perform_checks()
eGPUSupportLevel support_level = GPU_platform_support_level();
const char *platform_key = GPU_platform_support_level_key();
- /* check if previous check matches the current check. Don't update the approval when running in
- * `background`. this could have been triggered by installing addons via installers. */
+ /* Check if previous check matches the current check. Don't update the approval when running in
+ * `background`. this could have been triggered by installing add-ons via installers. */
if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup &&
wm_platform_support_check_approval(platform_key, !G.background)) {
- /* if it matches the user has confirmed and whishes to use it */
+ /* If it matches the user has confirmed and wishes to use it. */
return result;
}
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 02a8951e60e..58030920fc7 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1619,8 +1619,8 @@ void WM_main_playanim(int argc, const char **argv)
AUD_initOnce();
- if (!(audio_device = AUD_init("OpenAL", specs, 1024, "Blender"))) {
- audio_device = AUD_init("Null", specs, 0, "Blender");
+ if (!(audio_device = AUD_init(NULL, specs, 1024, "Blender"))) {
+ audio_device = AUD_init("None", specs, 0, "Blender");
}
}
#endif
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index ada4093080c..d75ba7865bd 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -216,7 +216,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
/* end running jobs, a job end also removes its timer */
LISTBASE_FOREACH_MUTABLE (wmTimer *, wt, &wm->timers) {
if (wt->win == win && wt->event_type == TIMERJOBS) {
- wm_jobs_timer_ended(wm, wt);
+ wm_jobs_timer_end(wm, wt);
}
}
@@ -520,7 +520,7 @@ void WM_window_set_dpi(const wmWindow *win)
static void wm_window_update_eventstate(wmWindow *win)
{
/* Update mouse position when a window is activated. */
- wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+ wm_cursor_position_get(win, &win->eventstate->x, &win->eventstate->y);
}
static void wm_window_ensure_eventstate(wmWindow *win)
@@ -983,15 +983,15 @@ void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
}
-void wm_get_cursor_position(wmWindow *win, int *x, int *y)
+void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
- *x = win->eventstate->x;
- *y = win->eventstate->y;
+ *r_x = win->eventstate->x;
+ *r_y = win->eventstate->y;
return;
}
- GHOST_GetCursorPosition(g_system, x, y);
- wm_cursor_position_from_ghost(win, x, y);
+ GHOST_GetCursorPosition(g_system, r_x, r_y);
+ wm_cursor_position_from_ghost(win, r_x, r_y);
}
typedef enum {
@@ -1691,7 +1691,7 @@ void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *
/* there might be events in queue with this timer as customdata */
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
- LISTBASE_FOREACH (wmEvent *, event, &win->queue) {
+ LISTBASE_FOREACH (wmEvent *, event, &win->event_queue) {
if (event->customdata == wt) {
event->customdata = NULL;
event->type = EVENT_NONE; /* timer users customdata, dont want NULL == NULL */
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index c26acfc9802..7fddf60eb97 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -71,14 +71,13 @@ void wm_tweakevent_test(bContext *C, const wmEvent *event, int action);
/* wm_jobs.c */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt);
-void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt);
+void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt);
/* wm_files.c */
void wm_autosave_timer(struct Main *bmain, wmWindowManager *wm, wmTimer *wt);
-void wm_autosave_timer_ended(wmWindowManager *wm);
+void wm_autosave_timer_begin(struct wmWindowManager *wm);
+void wm_autosave_timer_end(wmWindowManager *wm);
void wm_autosave_delete(void);
-void wm_autosave_read(bContext *C, struct ReportList *reports);
-void wm_autosave_location(char *filepath);
/* wm_splash_screen.c */
void WM_OT_splash(wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index b85616deda5..2842538ebf1 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -72,6 +72,7 @@ typedef enum WMCursorType {
WM_CURSOR_ZOOM_OUT,
WM_CURSOR_NONE,
+ WM_CURSOR_MUTE,
/* --- ALWAYS LAST ----- */
WM_CURSOR_NUM,
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 0ac67b987d7..f205f923ec8 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -69,8 +69,8 @@ void wm_window_swap_buffers(wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
-void wm_get_cursor_position(wmWindow *win, int *x, int *y);
-void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y);
+void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y);
+void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y);
void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y);
#ifdef WITH_INPUT_IME
diff --git a/source/creator/creator.c b/source/creator/creator.c
index fbc97028d35..b40718d1f7c 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -47,7 +47,7 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-/* Mostly init functions. */
+/* Mostly initialization functions. */
#include "BKE_appdir.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
@@ -109,8 +109,6 @@
#include "creator_intern.h" /* Own include. */
-/* Local Function prototypes. */
-
/* -------------------------------------------------------------------- */
/** \name Local Application State
* \{ */
@@ -264,7 +262,7 @@ int main(int argc,
# endif
/* Win32 Unicode Arguments. */
- /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized
+ /* NOTE: cannot use `guardedalloc` allocation here, as it's not yet initialized
* (it depends on the arguments passed in, which is what we're getting here!)
*/
{
@@ -453,8 +451,8 @@ int main(int argc,
/* Background render uses this font too. */
BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
- /* Initialize ffmpeg if built in, also needed for background-mode if videos are
- * rendered via ffmpeg. */
+ /* Initialize FFMPEG if built in, also needed for background-mode if videos are
+ * rendered via FFMPEG. */
BKE_sound_init_once();
BKE_materials_init();
@@ -524,7 +522,7 @@ int main(int argc,
#endif /* WITH_PYTHON_MODULE */
return 0;
-} /* End of int main(...) function. */
+} /* End of `int main(...)` function. */
#ifdef WITH_PYTHON_MODULE
void main_python_exit(void)
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 9133b259a13..d1899cc1408 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -610,6 +610,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf("\n");
printf("Misc Options:\n");
+ BLI_args_print_arg_doc(ba, "--open-last");
BLI_args_print_arg_doc(ba, "--app-template");
BLI_args_print_arg_doc(ba, "--factory-startup");
BLI_args_print_arg_doc(ba, "--enable-event-simulate");
@@ -868,6 +869,8 @@ static const char arg_handle_log_set_doc[] =
"\tEnable logging categories, taking a single comma separated argument.\n"
"\tMultiple categories can be matched using a '.*' suffix,\n"
"\tso '--log \"wm.*\"' logs every kind of window-manager message.\n"
+ "\tSub-string can be matched using a '*' prefix and suffix,\n"
+ "\tso '--log \"*undo*\"' logs every kind of undo-related message.\n"
"\tUse \"^\" prefix to ignore, so '--log \"*,^wm.operator.*\"' logs all except for "
"'wm.operators.*'\n"
"\tUse \"*\" to log everything.";
@@ -1148,7 +1151,7 @@ static const char arg_handle_env_system_set_doc_python[] =
static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data))
{
- /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */
+ /* `--env-system-scripts` -> `BLENDER_SYSTEM_SCRIPTS` */
char env[64] = "BLENDER";
char *ch_dst = env + 7; /* skip BLENDER */
@@ -1319,7 +1322,7 @@ static int arg_handle_audio_disable(int UNUSED(argc),
const char **UNUSED(argv),
void *UNUSED(data))
{
- BKE_sound_force_device("Null");
+ BKE_sound_force_device("None");
return 0;
}
@@ -1327,7 +1330,7 @@ static const char arg_handle_audio_set_doc[] =
"\n\t"
"Force sound system to a specific device."
"\n\t"
- "'NULL' 'SDL' 'OPENAL' 'JACK'.";
+ "'None' 'SDL' 'OpenAL' 'CoreAudio' 'JACK' 'PulseAudio' 'WASAPI'.";
static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
{
if (argc < 1) {
@@ -2008,7 +2011,7 @@ static int arg_handle_load_last_file(int UNUSED(argc), const char **UNUSED(argv)
const RecentFile *recent_file = G.recent_files.first;
const char *fake_argv[] = {recent_file->filepath};
- return arg_handle_load_file(1, fake_argv, data);
+ return arg_handle_load_file(ARRAY_SIZE(fake_argv), fake_argv, data);
}
void main_args_setup(bContext *C, bArgs *ba)
diff --git a/source/tools b/source/tools
-Subproject dc4ccc3bfb646ef2a558bd3565f84080e99b0e8
+Subproject b66c22e1fb977bf8dd3797ebedc28fbe28f0305
diff --git a/tests/gtests/runner/CMakeLists.txt b/tests/gtests/runner/CMakeLists.txt
index 1fe8cf21810..b18eff59016 100644
--- a/tests/gtests/runner/CMakeLists.txt
+++ b/tests/gtests/runner/CMakeLists.txt
@@ -82,6 +82,7 @@ elseif(APPLE)
# are used as dependencies of other test libraries.
foreach(_lib ${_test_libs})
list(REMOVE_ITEM _test_libs_dependencies ${_lib})
+ add_dependencies(blender_test ${_lib})
target_link_options(blender_test PRIVATE "LINKER:-force_load,$<TARGET_FILE:${_lib}>")
endforeach()
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index d8bc5be40d7..260eb75d64f 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -71,6 +71,12 @@ add_blender_test(
)
add_blender_test(
+ script_validate_keymap
+ --python ${CMAKE_CURRENT_LIST_DIR}/bl_keymap_validate.py
+ -- --relaxed # Disable minor things that should not cause tests to break.
+)
+
+add_blender_test(
script_load_addons
--python ${CMAKE_CURRENT_LIST_DIR}/bl_load_addons.py
)
diff --git a/tests/python/bl_blendfile_io.py b/tests/python/bl_blendfile_io.py
index 2c27b60f34e..38b3a93bbbc 100644
--- a/tests/python/bl_blendfile_io.py
+++ b/tests/python/bl_blendfile_io.py
@@ -15,7 +15,8 @@ class TestBlendFileSaveLoadBasic(TestHelper):
self.args = args
def test_save_load(self):
- bpy.ops.wm.read_factory_settings()
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
+
bpy.data.meshes.new("OrphanedMesh")
output_dir = self.args.output_dir
@@ -71,6 +72,9 @@ def argparse_create():
def main():
args = argparse_create().parse_args()
+ # Don't write thumbnails into the home directory.
+ bpy.context.preferences.filepaths.use_save_preview_images = False
+
for Test in TESTS:
Test(args).run_all_tests()
diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py
index fc618314216..a5f2571c902 100644
--- a/tests/python/bl_blendfile_liblink.py
+++ b/tests/python/bl_blendfile_liblink.py
@@ -15,7 +15,9 @@ class TestBlendLibLinkSaveLoadBasic(TestHelper):
self.args = args
def test_link_save_load(self):
- bpy.ops.wm.read_factory_settings()
+
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
+
me = bpy.data.meshes.new("LibMesh")
me.use_fake_user = True
@@ -26,7 +28,7 @@ class TestBlendLibLinkSaveLoadBasic(TestHelper):
bpy.ops.wm.save_as_mainfile(filepath=output_path, check_existing=False, compress=False)
- bpy.ops.wm.read_factory_settings()
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
bpy.data.orphans_purge()
link_dir = os.path.join(output_path, "Mesh")
@@ -68,6 +70,9 @@ def argparse_create():
def main():
args = argparse_create().parse_args()
+ # Don't write thumbnails into the home directory.
+ bpy.context.preferences.filepaths.use_save_preview_images = False
+
for Test in TESTS:
Test(args).run_all_tests()
diff --git a/tests/python/bl_keymap_validate.py b/tests/python/bl_keymap_validate.py
new file mode 100644
index 00000000000..88c61df6125
--- /dev/null
+++ b/tests/python/bl_keymap_validate.py
@@ -0,0 +1,241 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_keymap_validate.py
+#
+
+"""
+This catches the following kinds of issues:
+
+- Arguments that don't make sense, e.g.
+ - 'repeat' for non keyboard events.
+ - 'any' argument with other modifiers also enabled.
+ - Duplicate property entries.
+- Unknown/unused dictionary keys.
+- Unused keymaps (keymaps which are defined but not used anywhere).
+- Event values that don't make sense for the event type, e.g.
+ An escape key could have the value "NORTH" instead of "PRESS".
+
+This works by taking the keymap data (before it's loaded into Blender),
+then comparing it with that same keymap after exporting and imporing.
+
+NOTE:
+
+ Append ' -- --relaxed' not to fail on small issues,
+ this is so minor inconsistencies don't break the tests.
+"""
+
+import types
+import typing
+
+import contextlib
+
+import bpy
+
+# Useful for diffing the output to see what changed in context.
+# this writes keymaps into the current directory with `.orig.py` & `.rewrite.py` extensions.
+WRITE_OUTPUT_DIR = None # "/tmp", defaults to the systems temp directory.
+
+
+# -----------------------------------------------------------------------------
+# Generic Utilities
+
+@contextlib.contextmanager
+def temp_fn_argument_extractor(
+ mod: types.ModuleType,
+ mod_attr: str,
+) -> typing.Iterator[typing.List[typing.Tuple[list, dict]]]:
+ """
+ Temporarily intercept a function, so it's arguments can be extracted.
+ The context manager gives us a list where each item is a tuple of
+ arguments & keywords, stored each time the function was called.
+ """
+ args_collected = []
+ real_fn = getattr(mod, mod_attr)
+
+ def wrap_fn(*args, **kw):
+ args_collected.append((args, kw))
+ return real_fn(*args, **kw)
+ setattr(mod, mod_attr, wrap_fn)
+ try:
+ yield args_collected
+ finally:
+ setattr(mod, mod_attr, real_fn)
+
+
+def round_float_32(f: float) -> float:
+ from struct import pack, unpack
+ return unpack("f", pack("f", f))[0]
+
+
+def report_humanly_readable_difference(a: typing.Any, b: typing.Any) -> typing.Optional[str]:
+ """
+ Compare strings, return None whrn they match,
+ otherwise a humanly readable difference message.
+ """
+ import unittest
+ cls = unittest.TestCase()
+ try:
+ cls.assertEqual(a, b)
+ except AssertionError as ex:
+ return str(ex)
+ return None
+
+
+# -----------------------------------------------------------------------------
+# Keymap Utilities.
+
+def keyconfig_preset_scan() -> typing.List[str]:
+ """
+ Return all bundled presets (keymaps), not user presets.
+ """
+ import os
+ from bpy import context
+ # This assumes running with `--factory-settings`.
+ default_keyconfig = context.window_manager.keyconfigs.active.name
+ default_preset_filepath = bpy.utils.preset_find(default_keyconfig, "keyconfig")
+ dirname, filename = os.path.split(default_preset_filepath)
+ return [
+ os.path.join(dirname, f)
+ for f in sorted(os.listdir(dirname))
+ if f.lower().endswith(".py")
+ if not f.startswith((".", "_"))
+ ]
+
+
+def keymap_item_property_clean(value: typing.Any) -> typing.Any:
+ """
+ Recursive property sanitize.
+
+ - Make all floats 32bit (since internally they are).
+ - Sort all properties (since the order isn't important).
+ """
+ if type(value) is float:
+ # Once the value is loaded back from Blender, it will be 32bit.
+ return round_float_32(value)
+ if type(value) is list:
+ return sorted(
+ # Convert to `dict` to de-duplicate.
+ dict([(k, keymap_item_property_clean(v)) for k, v in value]).items(),
+ key=lambda item: item[0],
+ )
+ return value
+
+
+def keymap_data_clean(keyconfig_data: typing.List, *, relaxed: bool) -> None:
+ """
+ Order & sanitize keymap data so the result
+ from the hand written Python script is comparable with data exported & imported.
+ """
+ keyconfig_data.sort(key=lambda a: a[0])
+ for _, _, km_items_data in keyconfig_data:
+ items = km_items_data["items"]
+ for i, (item_op, item_event, item_prop) in enumerate(items):
+ if relaxed:
+ # Prevent "alt": False from raising an error.
+ defaults = {"alt": False, "ctrl": False, "shift": False, "any": False}
+ defaults.update(item_event)
+ item_event.update(defaults)
+
+ if item_prop:
+ properties = item_prop.get("properties")
+ if properties:
+ properties[:] = keymap_item_property_clean(properties)
+ else:
+ item_prop.pop("properties")
+
+ # Needed so: `{"properties": ()}` matches `None` as there is no meaningful difference.
+ # Wruting `None` makes the most sense when explicitly written, however generated properties
+ # might be empty and it's not worth adding checks in the generation logic to use `None`
+ # just to satisfy this check.
+ if not item_prop:
+ items[i] = item_op, item_event, None
+
+
+def keyconfig_activate_and_extract_data(filepath: str, *, relaxed: bool) -> typing.List:
+ """
+ Activate the key-map by filepath,
+ return the key-config data (cleaned for comparison).
+ """
+ import bl_keymap_utils.io
+ with temp_fn_argument_extractor(bl_keymap_utils.io, "keyconfig_init_from_data") as args_collected:
+ bpy.ops.preferences.keyconfig_activate(filepath=filepath)
+ # If called multiple times, something strange is happening.
+ assert(len(args_collected) == 1)
+ args, _kw = args_collected[0]
+ keyconfig_data = args[1]
+ keymap_data_clean(keyconfig_data, relaxed=relaxed)
+ return keyconfig_data
+
+
+def main() -> None:
+ import os
+ import sys
+ import pprint
+ import tempfile
+
+ argv = (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+
+ # Use `argparse` for full arg parsing, for now this is enough.
+ relaxed = "--relaxed" not in argv
+
+ has_error = False
+
+ presets = keyconfig_preset_scan()
+ for filepath in presets:
+ name_only = os.path.splitext(os.path.basename(filepath))[0]
+
+ print("KeyMap Validate:", name_only, end=" ... ")
+
+ data_orig = keyconfig_activate_and_extract_data(filepath, relaxed=relaxed)
+
+ with tempfile.TemporaryDirectory() as dir_temp:
+ filepath_temp = os.path.join(dir_temp, name_only + ".test.py")
+ bpy.ops.preferences.keyconfig_export(filepath=filepath_temp, all=True)
+ data_reimport = keyconfig_activate_and_extract_data(filepath_temp, relaxed=relaxed)
+
+ # Comparing a pretty printed string tends to give more useful
+ # text output compared to the data-structure. Both will work.
+ if (cmp_message := report_humanly_readable_difference(
+ pprint.pformat(data_orig, indent=0, width=120),
+ pprint.pformat(data_reimport, indent=0, width=120),
+ )):
+ print("FAILED!")
+ sys.stdout.write((
+ "Keymap %s has inconsistency on re-importing:\n"
+ " %r"
+ ) % (filepath, cmp_message))
+ has_error = True
+ else:
+ print("OK!")
+
+ if WRITE_OUTPUT_DIR:
+ name_only_temp = os.path.join(WRITE_OUTPUT_DIR, name_only)
+ print("Writing data to:", name_only_temp + ".*.py")
+ with open(name_only_temp + ".orig.py", 'w') as fh:
+ fh.write(pprint.pformat(data_orig, indent=0, width=120))
+ with open(name_only_temp + ".rewrite.py", 'w') as fh:
+ fh.write(pprint.pformat(data_reimport, indent=0, width=120))
+ if has_error:
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()